Use Tempest plugin interface

Make use of the Tempest plugin interface instead of copying Manila
files into Tempest. This will remove the burden to port Manila
tests onto Tempest master recurrently.

This ports all existing Manila Tempest test to the new structure.

It uses manila_tempest_tests as new top folder for all Tempest
tests. It follow the model of Heat (see [1]).

[1]: https://github.com/openstack/heat/tree/master/heat_integrationtests

Change-Id: Ie5ed64a6777ed1acf8dd56522c26705ae897596d
Partly-implements: bp tempest-plugin-interface
Depends-On: I26dd32b1de8cceeaa6dc674092efec683df71889
This commit is contained in:
Marc Koderer 2015-07-15 09:18:35 +02:00 committed by Ben Swartzlander
commit 0abc93b859
55 changed files with 8129 additions and 0 deletions

View File

@ -0,0 +1,6 @@
====================
Tempest Integration
====================
This directory contains Tempest tests to cover Manila project.

View File

View File

@ -0,0 +1,38 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import clients
from tempest.common import cred_provider
from manila_tempest_tests.services.share.json import shares_client
class Manager(clients.Manager):
def __init__(self, credentials=None, service=None):
super(Manager, self).__init__(credentials, service)
self.shares_client = shares_client.SharesClient(self.auth_provider)
class AltManager(Manager):
def __init__(self, service=None):
super(AltManager, self).__init__(
cred_provider.get_configured_credentials('alt_user'), service)
class AdminManager(Manager):
def __init__(self, service=None):
super(AdminManager, self).__init__(
cred_provider.get_configured_credentials('identity_admin'),
service)

View File

@ -0,0 +1,154 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import print_function
from oslo_config import cfg
from tempest import config # noqa
service_available_group = cfg.OptGroup(name="service_available",
title="Available OpenStack Services")
ServiceAvailableGroup = [
cfg.BoolOpt("manila",
default=True,
help="Whether or not manila is expected to be available"),
]
share_group = cfg.OptGroup(name="share", title="Share Service Options")
ShareGroup = [
cfg.StrOpt("min_api_microversion",
default="1.0",
help="The minimum api microversion is configured to be the "
"value of the minimum microversion supported by Manila."),
cfg.StrOpt("max_api_microversion",
default="1.4",
help="The maximum api microversion is configured to be the "
"value of the latest microversion supported by Manila."),
cfg.StrOpt("region",
default="",
help="The share region name to use. If empty, the value "
"of identity.region is used instead. If no such region "
"is found in the service catalog, the first found one is "
"used."),
cfg.StrOpt("catalog_type",
default="share",
help="Catalog type of the Share service."),
cfg.StrOpt('endpoint_type',
default='publicURL',
choices=['public', 'admin', 'internal',
'publicURL', 'adminURL', 'internalURL'],
help="The endpoint type to use for the share service."),
cfg.BoolOpt("multitenancy_enabled",
default=True,
help="This option used to determine backend driver type, "
"multitenant driver uses share-networks, but "
"single-tenant doesn't."),
cfg.ListOpt("enable_protocols",
default=["nfs", "cifs"],
help="First value of list is protocol by default, "
"items of list show enabled protocols at all."),
cfg.ListOpt("enable_ip_rules_for_protocols",
default=["nfs", "cifs", ],
help="Selection of protocols, that should "
"be covered with ip rule tests"),
cfg.ListOpt("enable_user_rules_for_protocols",
default=[],
help="Selection of protocols, that should "
"be covered with user rule tests"),
cfg.ListOpt("enable_cert_rules_for_protocols",
default=["glusterfs", ],
help="Protocols that should be covered with cert rule tests."),
cfg.StrOpt("username_for_user_rules",
default="Administrator",
help="Username, that will be used in user tests."),
cfg.ListOpt("enable_ro_access_level_for_protocols",
default=["nfs", ],
help="List of protocols to run tests with ro access level."),
cfg.StrOpt("storage_protocol",
default="NFS_CIFS",
help="Backend protocol to target when creating volume types."),
cfg.StrOpt("share_network_id",
default="",
help="Some backend drivers requires share network "
"for share creation. Share network id, that will be "
"used for shares. If not set, it won't be used."),
cfg.StrOpt("alt_share_network_id",
default="",
help="Share network id, that will be used for shares"
" in alt tenant. If not set, it won't be used"),
cfg.StrOpt("admin_share_network_id",
default="",
help="Share network id, that will be used for shares"
" in admin tenant. If not set, it won't be used"),
cfg.BoolOpt("multi_backend",
default=False,
help="Runs Manila multi-backend tests."),
cfg.ListOpt("backend_names",
default=[],
help="Names of share backends, that will be used with "
"multibackend tests. Tempest will use first two values."),
cfg.IntOpt("share_creation_retry_number",
default=0,
help="Defines number of retries for share creation. "
"It is useful to avoid failures caused by unstable "
"environment."),
cfg.IntOpt("build_interval",
default=3,
help="Time in seconds between share availability checks."),
cfg.IntOpt("build_timeout",
default=500,
help="Timeout in seconds to wait for a share to become"
"available."),
cfg.BoolOpt("suppress_errors_in_cleanup",
default=False,
help="Whether to suppress errors with clean up operation "
"or not. There are cases when we may want to skip "
"such errors and catch only test errors."),
cfg.BoolOpt("run_manage_unmanage_tests",
default=False,
help="Defines whether to run manage/unmanage tests or not. "
"These test may leave orphaned resources, so be careful "
"enabling this opt."),
cfg.BoolOpt("run_extend_tests",
default=True,
help="Defines whether to run share extend tests or not. "
"Disable this feature if used driver doesn't "
"support it."),
cfg.BoolOpt("run_shrink_tests",
default=True,
help="Defines whether to run share shrink tests or not. "
"Disable this feature if used driver doesn't "
"support it."),
cfg.BoolOpt("run_snapshot_tests",
default=True,
help="Defines whether to run tests that use share snapshots "
"or not. Disable this feature if used driver doesn't "
"support it."),
cfg.StrOpt("image_with_share_tools",
default="manila-service-image",
help="Image name for vm booting with nfs/smb clients tool."),
cfg.StrOpt("image_username",
default="manila",
help="Image username."),
cfg.StrOpt("image_password",
help="Image password. Should be used for "
"'image_with_share_tools' without Nova Metadata support."),
cfg.StrOpt("client_vm_flavor_ref",
default="100",
help="Flavor used for client vm in scenario tests."),
]

View File

@ -0,0 +1,41 @@
# Copyright 2015 Deutsche Telekom AG
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
from tempest import config
from tempest.test_discover import plugins
from manila_tempest_tests import config as config_share
class ManilaTempestPlugin(plugins.TempestPlugin):
def load_tests(self):
base_path = os.path.split(os.path.dirname(
os.path.abspath(__file__)))[0]
test_dir = "manila_tempest_tests/tests"
full_test_dir = os.path.join(base_path, test_dir)
return full_test_dir, base_path
def register_opts(self, conf):
config.register_opt_group(
conf, config_share.service_available_group,
config_share.ServiceAvailableGroup)
config.register_opt_group(conf, config_share.share_group,
config_share.ShareGroup)
def get_opt_lists(self):
return [(config_share.share_group.name, config_share.ShareGroup)]

View File

@ -0,0 +1,821 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import json
import time
import urllib
import six
from tempest import config # noqa
from tempest_lib.common import rest_client
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions
from manila_tempest_tests import share_exceptions
CONF = config.CONF
class SharesClient(rest_client.RestClient):
"""Tempest REST client for Manila.
It handles shares and access to it in OpenStack.
"""
def __init__(self, auth_provider):
super(SharesClient, self).__init__(
auth_provider,
CONF.share.catalog_type,
CONF.share.region or CONF.identity.region,
endpoint_type=CONF.share.endpoint_type)
self.share_protocol = None
if CONF.share.enable_protocols:
self.share_protocol = CONF.share.enable_protocols[0]
self.share_network_id = CONF.share.share_network_id
self.build_interval = CONF.share.build_interval
self.build_timeout = CONF.share.build_timeout
self.API_MICROVERSIONS_HEADER = 'x-openstack-manila-api-version'
def _get_version_dict(self, version):
return {self.API_MICROVERSIONS_HEADER: version}
def send_microversion_request(self, version=None):
"""Prepare and send the HTTP GET Request to the base URL.
Extracts the base URL from the shares_client endpoint and makes a GET
request with the microversions request header.
"""
headers = self.get_headers()
url, headers, body = self.auth_provider.auth_request(
'GET', 'shares', headers, None, self.filters)
url = '/'.join(url.split('/')[:3]) + '/'
if version:
headers[self.API_MICROVERSIONS_HEADER] = version
resp, resp_body = self.raw_request(url, 'GET', headers=headers)
self.response_checker('GET', resp, resp_body)
resp_body = json.loads(resp_body)
return resp, resp_body
def create_share(self, share_protocol=None, size=1,
name=None, snapshot_id=None, description=None,
metadata=None, share_network_id=None,
share_type_id=None, is_public=False):
metadata = metadata or {}
if name is None:
name = data_utils.rand_name("tempest-created-share")
if description is None:
description = data_utils.rand_name("tempest-created-share-desc")
if share_protocol is None:
share_protocol = self.share_protocol
if share_protocol is None:
raise share_exceptions.ShareProtocolNotSpecified()
post_body = {
"share": {
"share_proto": share_protocol,
"description": description,
"snapshot_id": snapshot_id,
"name": name,
"size": size,
"metadata": metadata,
"is_public": is_public,
}
}
if share_network_id:
post_body["share"]["share_network_id"] = share_network_id
if share_type_id:
post_body["share"]["share_type"] = share_type_id
body = json.dumps(post_body)
resp, body = self.post("shares", body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_share(self, share_id):
resp, body = self.delete("shares/%s" % share_id)
self.expected_success(202, resp.status)
return body
def manage_share(self, service_host, protocol, export_path,
share_type_id, name=None, description=None):
post_body = {
"share": {
"export_path": export_path,
"service_host": service_host,
"protocol": protocol,
"share_type": share_type_id,
"name": name,
"description": description,
}
}
body = json.dumps(post_body)
resp, body = self.post("os-share-manage", body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def unmanage_share(self, share_id):
resp, body = self.post(
"os-share-unmanage/%s/unmanage" % share_id, None)
self.expected_success(202, resp.status)
return body
def list_shares(self, detailed=False, params=None):
"""Get list of shares w/o filters."""
uri = 'shares/detail' if detailed else 'shares'
uri += '?%s' % urllib.urlencode(params) if params else ''
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_shares_with_detail(self, params=None):
"""Get detailed list of shares w/o filters."""
return self.list_shares(detailed=True, params=params)
def get_share(self, share_id):
resp, body = self.get("shares/%s" % share_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_instances_of_share(self, share_id):
resp, body = self.get("shares/%s/instances" % share_id,
headers=self._get_version_dict('1.4'),
extra_headers=True)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_share_instances(self):
resp, body = self.get("share_instances",
headers=self._get_version_dict('1.4'),
extra_headers=True)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_share_instance(self, instance_id):
resp, body = self.get("share_instances/%s" % instance_id,
headers=self._get_version_dict('1.4'),
extra_headers=True)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_access_rule(self, share_id, access_type="ip",
access_to="0.0.0.0", access_level=None):
post_body = {
"os-allow_access": {
"access_type": access_type,
"access_to": access_to,
"access_level": access_level,
}
}
body = json.dumps(post_body)
resp, body = self.post("shares/%s/action" % share_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_access_rules(self, share_id):
body = {"os-access_list": None}
resp, body = self.post("shares/%s/action" % share_id, json.dumps(body))
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_access_rule(self, share_id, rule_id):
post_body = {
"os-deny_access": {
"access_id": rule_id,
}
}
body = json.dumps(post_body)
resp, body = self.post("shares/%s/action" % share_id, body)
self.expected_success(202, resp.status)
return body
def extend_share(self, share_id, new_size):
post_body = {
"os-extend": {
"new_size": new_size,
}
}
body = json.dumps(post_body)
resp, body = self.post("shares/%s/action" % share_id, body)
self.expected_success(202, resp.status)
return body
def shrink_share(self, share_id, new_size):
post_body = {
"os-shrink": {
"new_size": new_size,
}
}
body = json.dumps(post_body)
resp, body = self.post("shares/%s/action" % share_id, body)
self.expected_success(202, resp.status)
return body
def create_snapshot(self, share_id, name=None, description=None,
force=False):
if name is None:
name = data_utils.rand_name("tempest-created-share-snap")
if description is None:
description = data_utils.rand_name(
"tempest-created-share-snap-desc")
post_body = {
"snapshot": {
"name": name,
"force": force,
"description": description,
"share_id": share_id,
}
}
body = json.dumps(post_body)
resp, body = self.post("snapshots", body)
self.expected_success(202, resp.status)
return self._parse_resp(body)
def get_snapshot(self, snapshot_id):
resp, body = self.get("snapshots/%s" % snapshot_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_snapshots(self, detailed=False, params=None):
"""Get list of share snapshots w/o filters."""
uri = 'snapshots/detail' if detailed else 'snapshots'
uri += '?%s' % urllib.urlencode(params) if params else ''
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_snapshots_with_detail(self, params=None):
"""Get detailed list of share snapshots w/o filters."""
return self.list_snapshots(detailed=True, params=params)
def delete_snapshot(self, snap_id):
resp, body = self.delete("snapshots/%s" % snap_id)
self.expected_success(202, resp.status)
return body
def wait_for_share_status(self, share_id, status):
"""Waits for a share to reach a given status."""
body = self.get_share(share_id)
share_name = body['name']
share_status = body['status']
start = int(time.time())
while share_status != status:
time.sleep(self.build_interval)
body = self.get_share(share_id)
share_status = body['status']
if share_status == status:
return
elif 'error' in share_status.lower():
raise share_exceptions.\
ShareBuildErrorException(share_id=share_id)
if int(time.time()) - start >= self.build_timeout:
message = ('Share %s failed to reach %s status within '
'the required time (%s s).' %
(share_name, status, self.build_timeout))
raise exceptions.TimeoutException(message)
def wait_for_share_instance_status(self, instance_id, status):
"""Waits for a share to reach a given status."""
body = self.get_share_instance(instance_id)
instance_status = body['status']
start = int(time.time())
while instance_status != status:
time.sleep(self.build_interval)
body = self.get_share(instance_id)
instance_status = body['status']
if instance_status == status:
return
elif 'error' in instance_status.lower():
raise share_exceptions.\
ShareInstanceBuildErrorException(id=instance_id)
if int(time.time()) - start >= self.build_timeout:
message = ('Share instance %s failed to reach %s status within'
' the required time (%s s).' %
(instance_id, status, self.build_timeout))
raise exceptions.TimeoutException(message)
def wait_for_snapshot_status(self, snapshot_id, status):
"""Waits for a snapshot to reach a given status."""
body = self.get_snapshot(snapshot_id)
snapshot_name = body['name']
snapshot_status = body['status']
start = int(time.time())
while snapshot_status != status:
time.sleep(self.build_interval)
body = self.get_snapshot(snapshot_id)
snapshot_status = body['status']
if 'error' in snapshot_status:
raise exceptions.\
SnapshotBuildErrorException(snapshot_id=snapshot_id)
if int(time.time()) - start >= self.build_timeout:
message = ('Share Snapshot %s failed to reach %s status '
'within the required time (%s s).' %
(snapshot_name, status, self.build_timeout))
raise exceptions.TimeoutException(message)
def wait_for_access_rule_status(self, share_id, rule_id, status):
"""Waits for an access rule to reach a given status."""
rule_status = "new"
start = int(time.time())
while rule_status != status:
time.sleep(self.build_interval)
rules = self.list_access_rules(share_id)
for rule in rules:
if rule["id"] in rule_id:
rule_status = rule['state']
break
if 'error' in rule_status:
raise share_exceptions.\
AccessRuleBuildErrorException(rule_id=rule_id)
if int(time.time()) - start >= self.build_timeout:
message = ('Share Access Rule %s failed to reach %s status '
'within the required time (%s s).' %
(rule_id, status, self.build_timeout))
raise exceptions.TimeoutException(message)
def default_quotas(self, tenant_id):
resp, body = self.get("os-quota-sets/%s/defaults" % tenant_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def show_quotas(self, tenant_id, user_id=None):
uri = "os-quota-sets/%s" % tenant_id
if user_id is not None:
uri += "?user_id=%s" % user_id
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def reset_quotas(self, tenant_id, user_id=None):
uri = "os-quota-sets/%s" % tenant_id
if user_id is not None:
uri += "?user_id=%s" % user_id
resp, body = self.delete(uri)
self.expected_success(202, resp.status)
return body
def update_quotas(self, tenant_id, user_id=None, shares=None,
snapshots=None, gigabytes=None, snapshot_gigabytes=None,
share_networks=None, force=True):
uri = "os-quota-sets/%s" % tenant_id
if user_id is not None:
uri += "?user_id=%s" % user_id
put_body = {"tenant_id": tenant_id}
if force:
put_body["force"] = "true"
if shares is not None:
put_body["shares"] = shares
if snapshots is not None:
put_body["snapshots"] = snapshots
if gigabytes is not None:
put_body["gigabytes"] = gigabytes
if snapshot_gigabytes is not None:
put_body["snapshot_gigabytes"] = snapshot_gigabytes
if share_networks is not None:
put_body["share_networks"] = share_networks
put_body = json.dumps({"quota_set": put_body})
resp, body = self.put(uri, put_body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_limits(self):
resp, body = self.get("limits")
self.expected_success(200, resp.status)
return self._parse_resp(body)
def is_resource_deleted(self, *args, **kwargs):
"""Verifies whether provided resource deleted or not.
:param kwargs: dict with expected keys 'share_id', 'snapshot_id',
:param kwargs: 'sn_id', 'ss_id', 'vt_id' and 'server_id'
:raises share_exceptions.InvalidResource
"""
if "share_id" in kwargs:
if "rule_id" in kwargs:
rule_id = kwargs.get("rule_id")
share_id = kwargs.get("share_id")
rules = self.list_access_rules(share_id)
for rule in rules:
if rule["id"] == rule_id:
return False
return True
else:
return self._is_resource_deleted(
self.get_share, kwargs.get("share_id"))
elif "share_instance_id" in kwargs:
return self._is_resource_deleted(
self.get_share_instance, kwargs.get("share_instance_id"))
elif "snapshot_id" in kwargs:
return self._is_resource_deleted(
self.get_snapshot, kwargs.get("snapshot_id"))
elif "sn_id" in kwargs:
return self._is_resource_deleted(
self.get_share_network, kwargs.get("sn_id"))
elif "ss_id" in kwargs:
return self._is_resource_deleted(
self.get_security_service, kwargs.get("ss_id"))
elif "vt_id" in kwargs:
return self._is_resource_deleted(
self.get_volume_type, kwargs.get("vt_id"))
elif "st_id" in kwargs:
return self._is_resource_deleted(
self.get_share_type, kwargs.get("st_id"))
elif "server_id" in kwargs:
return self._is_resource_deleted(
self.show_share_server, kwargs.get("server_id"))
else:
raise share_exceptions.InvalidResource(
message=six.text_type(kwargs))
def _is_resource_deleted(self, func, res_id):
try:
res = func(res_id)
except exceptions.NotFound:
return True
if res.get('status') == 'error_deleting':
# Resource has "error_deleting" status and can not be deleted.
resource_type = func.__name__.split('_', 1)[-1]
raise share_exceptions.ResourceReleaseFailed(
res_type=resource_type, res_id=res_id)
return False
def wait_for_resource_deletion(self, *args, **kwargs):
"""Waits for a resource to be deleted."""
start_time = int(time.time())
while True:
if self.is_resource_deleted(*args, **kwargs):
return
if int(time.time()) - start_time >= self.build_timeout:
raise exceptions.TimeoutException
time.sleep(self.build_interval)
def list_extensions(self):
resp, extensions = self.get("extensions")
self.expected_success(200, resp.status)
return self._parse_resp(extensions)
def update_share(self, share_id, name=None, desc=None, is_public=None):
body = {"share": {}}
if name is not None:
body["share"].update({"display_name": name})
if desc is not None:
body["share"].update({"display_description": desc})
if is_public is not None:
body["share"].update({"is_public": is_public})
body = json.dumps(body)
resp, body = self.put("shares/%s" % share_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def rename_snapshot(self, snapshot_id, name, desc=None):
body = {"snapshot": {"display_name": name}}
if desc is not None:
body["snapshot"].update({"display_description": desc})
body = json.dumps(body)
resp, body = self.put("snapshots/%s" % snapshot_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def reset_state(self, s_id, status="error", s_type="shares"):
"""Resets the state of a share or a snapshot.
status: available, error, creating, deleting, error_deleting
s_type: shares, snapshots
"""
body = {"os-reset_status": {"status": status}}
body = json.dumps(body)
resp, body = self.post("%s/%s/action" % (s_type, s_id), body)
self.expected_success(202, resp.status)
return body
def force_delete(self, s_id, s_type="shares"):
"""Force delete share or snapshot.
s_type: shares, snapshots
"""
body = {"os-force_delete": None}
body = json.dumps(body)
resp, body = self.post("%s/%s/action" % (s_type, s_id), body)
self.expected_success(202, resp.status)
return body
###############
def list_services(self, params=None):
"""List services."""
uri = 'os-services'
if params:
uri += '?%s' % urllib.urlencode(params)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
###############
def _update_metadata(self, share_id, metadata=None, method="post"):
uri = "shares/%s/metadata" % share_id
if metadata is None:
metadata = {}
post_body = {"metadata": metadata}
body = json.dumps(post_body)
if method is "post":
resp, metadata = self.post(uri, body)
if method is "put":
resp, metadata = self.put(uri, body)
self.expected_success(200, resp.status)
return self._parse_resp(metadata)
def set_metadata(self, share_id, metadata=None):
return self._update_metadata(share_id, metadata)
def update_all_metadata(self, share_id, metadata=None):
return self._update_metadata(share_id, metadata, method="put")
def delete_metadata(self, share_id, key):
resp, body = self.delete("shares/%s/metadata/%s" % (share_id, key))
self.expected_success(200, resp.status)
return body
def get_metadata(self, share_id):
resp, body = self.get("shares/%s/metadata" % share_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
###############
def create_security_service(self, ss_type="ldap", **kwargs):
# ss_type: ldap, kerberos, active_directory
# kwargs: name, description, dns_ip, server, domain, user, password
post_body = {"type": ss_type}
post_body.update(kwargs)
body = json.dumps({"security_service": post_body})
resp, body = self.post("security-services", body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def update_security_service(self, ss_id, **kwargs):
# ss_id - id of security-service entity
# kwargs: dns_ip, server, domain, user, password, name, description
# for 'active' status can be changed
# only 'name' and 'description' fields
body = json.dumps({"security_service": kwargs})
resp, body = self.put("security-services/%s" % ss_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_security_service(self, ss_id):
resp, body = self.get("security-services/%s" % ss_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_security_services(self, detailed=False, params=None):
uri = "security-services"
if detailed:
uri += '/detail'
if params:
uri += "?%s" % urllib.urlencode(params)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_security_service(self, ss_id):
resp, body = self.delete("security-services/%s" % ss_id)
self.expected_success(202, resp.status)
return body
###############
def create_share_network(self, **kwargs):
# kwargs: name, description
# + for neutron: neutron_net_id, neutron_subnet_id
body = json.dumps({"share_network": kwargs})
resp, body = self.post("share-networks", body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def update_share_network(self, sn_id, **kwargs):
# kwargs: name, description
# + for neutron: neutron_net_id, neutron_subnet_id
body = json.dumps({"share_network": kwargs})
resp, body = self.put("share-networks/%s" % sn_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_share_network(self, sn_id):
resp, body = self.get("share-networks/%s" % sn_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_share_networks(self):
resp, body = self.get("share-networks")
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_share_networks_with_detail(self, params=None):
"""List the details of all shares."""
uri = "share-networks/detail"
if params:
uri += "?%s" % urllib.urlencode(params)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_share_network(self, sn_id):
resp, body = self.delete("share-networks/%s" % sn_id)
self.expected_success(202, resp.status)
return body
###############
def _map_security_service_and_share_network(self, sn_id, ss_id,
action="add"):
# sn_id: id of share_network_entity
# ss_id: id of security service entity
# action: add, remove
data = {
"%s_security_service" % action: {
"security_service_id": ss_id,
}
}
body = json.dumps(data)
resp, body = self.post("share-networks/%s/action" % sn_id, body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def add_sec_service_to_share_network(self, sn_id, ss_id):
body = self._map_security_service_and_share_network(sn_id, ss_id)
return body
def remove_sec_service_from_share_network(self, sn_id, ss_id):
body = self._map_security_service_and_share_network(
sn_id, ss_id, "remove")
return body
def list_sec_services_for_share_network(self, sn_id):
resp, body = self.get("security-services?share_network_id=%s" % sn_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
###############
def list_share_types(self, params=None):
uri = 'types'
if params is not None:
uri += '?%s' % urllib.urlencode(params)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def create_share_type(self, name, is_public=True, **kwargs):
post_body = {
'name': name,
'extra_specs': kwargs.get('extra_specs'),
'os-share-type-access:is_public': is_public,
}
post_body = json.dumps({'share_type': post_body})
resp, body = self.post('types', post_body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_share_type(self, share_type_id):
resp, body = self.delete("types/%s" % share_type_id)
self.expected_success(202, resp.status)
return body
def get_share_type(self, share_type_id):
resp, body = self.get("types/%s" % share_type_id)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def add_access_to_share_type(self, share_type_id, project_id):
uri = 'types/%s/action' % share_type_id
post_body = {'project': project_id}
post_body = json.dumps({'addProjectAccess': post_body})
resp, body = self.post(uri, post_body)
self.expected_success(202, resp.status)
return body
def remove_access_from_share_type(self, share_type_id, project_id):
uri = 'types/%s/action' % share_type_id
post_body = {'project': project_id}
post_body = json.dumps({'removeProjectAccess': post_body})
resp, body = self.post(uri, post_body)
self.expected_success(202, resp.status)
return body
def list_access_to_share_type(self, share_type_id):
uri = 'types/%s/os-share-type-access' % share_type_id
resp, body = self.get(uri)
# [{"share_type_id": "%st_id%", "project_id": "%project_id%"}, ]
self.expected_success(200, resp.status)
return self._parse_resp(body)
###############
def create_share_type_extra_specs(self, share_type_id, extra_specs):
url = "types/%s/extra_specs" % share_type_id
post_body = json.dumps({'extra_specs': extra_specs})
resp, body = self.post(url, post_body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_share_type_extra_spec(self, share_type_id, extra_spec_name):
uri = "types/%s/extra_specs/%s" % (share_type_id, extra_spec_name)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def get_share_type_extra_specs(self, share_type_id, params=None):
uri = "types/%s/extra_specs" % share_type_id
if params is not None:
uri += '?%s' % urllib.urlencode(params)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def update_share_type_extra_spec(self, share_type_id, spec_name,
spec_value):
uri = "types/%s/extra_specs/%s" % (share_type_id, spec_name)
extra_spec = {spec_name: spec_value}
post_body = json.dumps(extra_spec)
resp, body = self.put(uri, post_body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def update_share_type_extra_specs(self, share_type_id, extra_specs):
uri = "types/%s/extra_specs" % share_type_id
extra_specs = {"extra_specs": extra_specs}
post_body = json.dumps(extra_specs)
resp, body = self.post(uri, post_body)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_share_type_extra_spec(self, share_type_id, extra_spec_name):
uri = "types/%s/extra_specs/%s" % (share_type_id, extra_spec_name)
resp, body = self.delete(uri)
self.expected_success(202, resp.status)
return body
###############
def list_share_servers(self, search_opts=None):
"""Get list of share servers."""
uri = "share-servers"
if search_opts:
uri += "?%s" % urllib.urlencode(search_opts)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def delete_share_server(self, share_server_id):
"""Delete share server by its ID."""
uri = "share-servers/%s" % share_server_id
resp, body = self.delete(uri)
self.expected_success(202, resp.status)
return body
def show_share_server(self, share_server_id):
"""Get share server info."""
uri = "share-servers/%s" % share_server_id
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
def show_share_server_details(self, share_server_id):
"""Get share server details only."""
uri = "share-servers/%s/details" % share_server_id
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return self._parse_resp(body)
###############
def list_pools(self, detail=False, search_opts=None):
"""Get list of scheduler pools."""
uri = 'scheduler-stats/pools'
if detail:
uri += '/detail'
if search_opts:
uri += "?%s" % urllib.urlencode(search_opts)
resp, body = self.get(uri)
self.expected_success(200, resp.status)
return json.loads(body)

View File

@ -0,0 +1,52 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest_lib import exceptions
class ShareBuildErrorException(exceptions.TempestException):
message = "Share %(share_id)s failed to build and is in ERROR status"
class ShareInstanceBuildErrorException(exceptions.TempestException):
message = "Share instance %(id)s failed to build and is in ERROR status"
class AccessRuleBuildErrorException(exceptions.TempestException):
message = "Share's rule with id %(rule_id)s is in ERROR status"
class SnapshotBuildErrorException(exceptions.TempestException):
message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
class ShareProtocolNotSpecified(exceptions.TempestException):
message = "Share can not be created, share protocol is not specified"
class ShareNetworkNotSpecified(exceptions.TempestException):
message = "Share can not be created, share network not specified"
class NoAvailableNetwork(exceptions.TempestException):
message = "No available network for service VM"
class InvalidResource(exceptions.TempestException):
message = "Provided invalid resource: %(message)s"
class ResourceReleaseFailed(exceptions.TempestException):
message = "Failed to release resource '%(res_type)s' with id '%(res_id)s'."

View File

View File

@ -0,0 +1,117 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class AdminActionsTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(AdminActionsTest, cls).resource_setup()
cls.states = ["error", "available"]
cls.bad_status = "error_deleting"
cls.sh = cls.create_share()
cls.sh_instance = (
cls.shares_client.get_instances_of_share(cls.sh["id"])[0]
)
if CONF.share.run_snapshot_tests:
cls.sn = cls.create_snapshot_wait_for_active(cls.sh["id"])
@test.attr(type=["gate", ])
def test_reset_share_state(self):
for status in self.states:
self.shares_client.reset_state(self.sh["id"], status=status)
self.shares_client.wait_for_share_status(self.sh["id"], status)
@test.attr(type=["gate", ])
def test_reset_share_instance_state(self):
id = self.sh_instance["id"]
for status in self.states:
self.shares_client.reset_state(
id, s_type="share_instances", status=status)
self.shares_client.wait_for_share_instance_status(id, status)
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_reset_snapshot_state_to_error(self):
for status in self.states:
self.shares_client.reset_state(
self.sn["id"], s_type="snapshots", status=status)
self.shares_client.wait_for_snapshot_status(self.sn["id"], status)
@test.attr(type=["gate", ])
def test_force_delete_share(self):
share = self.create_share()
# Change status from 'available' to 'error_deleting'
self.shares_client.reset_state(share["id"], status=self.bad_status)
# Check that status was changed
check_status = self.shares_client.get_share(share["id"])
self.assertEqual(check_status["status"], self.bad_status)
# Share with status 'error_deleting' should be deleted
self.shares_client.force_delete(share["id"])
self.shares_client.wait_for_resource_deletion(share_id=share["id"])
@test.attr(type=["gate", ])
def test_force_delete_share_instance(self):
share = self.create_share(cleanup_in_class=False)
instances = self.shares_client.get_instances_of_share(share["id"])
# Check that instance was created
self.assertEqual(1, len(instances))
instance = instances[0]
# Change status from 'available' to 'error_deleting'
self.shares_client.reset_state(
instance["id"], s_type="share_instances", status=self.bad_status)
# Check that status was changed
check_status = self.shares_client.get_share_instance(instance["id"])
self.assertEqual(self.bad_status, check_status["status"])
# Share with status 'error_deleting' should be deleted
self.shares_client.force_delete(
instance["id"], s_type="share_instances")
self.shares_client.wait_for_resource_deletion(
share_instance_id=instance["id"])
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_force_delete_snapshot(self):
sn = self.create_snapshot_wait_for_active(self.sh["id"])
# Change status from 'available' to 'error_deleting'
self.shares_client.reset_state(
sn["id"], s_type="snapshots", status=self.bad_status)
# Check that status was changed
check_status = self.shares_client.get_snapshot(sn["id"])
self.assertEqual(check_status["status"], self.bad_status)
# Snapshot with status 'error_deleting' should be deleted
self.shares_client.force_delete(sn["id"], s_type="snapshots")
self.shares_client.wait_for_resource_deletion(snapshot_id=sn["id"])

View File

@ -0,0 +1,167 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests import clients_share as clients
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class AdminActionsNegativeTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(AdminActionsNegativeTest, cls).resource_setup()
cls.sh = cls.create_share()
cls.sh_instance = (
cls.shares_client.get_instances_of_share(cls.sh["id"])[0]
)
if CONF.share.run_snapshot_tests:
cls.sn = cls.create_snapshot_wait_for_active(cls.sh["id"])
cls.member_shares_client = clients.Manager().shares_client
@test.attr(type=["gate", "negative", ])
def test_reset_nonexistent_share_state(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.reset_state, "fake")
@test.attr(type=["gate", "negative", ])
def test_reset_nonexistent_share_instance_state(self):
self.assertRaises(lib_exc.NotFound, self.shares_client.reset_state,
"fake", s_type="share_instances")
@test.attr(type=["gate", "negative", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_reset_nonexistent_snapshot_state(self):
self.assertRaises(lib_exc.NotFound, self.shares_client.reset_state,
"fake", s_type="snapshots")
@test.attr(type=["gate", "negative", ])
def test_reset_share_state_to_unacceptable_state(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.reset_state,
self.sh["id"], status="fake")
@test.attr(type=["gate", "negative", ])
def test_reset_share_instance_state_to_unacceptable_state(self):
self.assertRaises(
lib_exc.BadRequest,
self.shares_client.reset_state,
self.sh_instance["id"],
s_type="share_instances",
status="fake"
)
@test.attr(type=["gate", "negative", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_reset_snapshot_state_to_unacceptable_state(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.reset_state,
self.sn["id"], s_type="snapshots", status="fake")
@test.attr(type=["gate", "negative", ])
def test_try_reset_share_state_with_member(self):
# Even if member from another tenant, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.reset_state,
self.sh["id"])
@test.attr(type=["gate", "negative", ])
def test_try_reset_share_instance_state_with_member(self):
# Even if member from another tenant, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.reset_state,
self.sh_instance["id"], s_type="share_instances")
@test.attr(type=["gate", "negative", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_try_reset_snapshot_state_with_member(self):
# Even if member from another tenant, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.reset_state,
self.sn["id"], s_type="snapshots")
@test.attr(type=["gate", "negative", ])
def test_force_delete_nonexistent_share(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.force_delete, "fake")
@test.attr(type=["gate", "negative", ])
def test_force_delete_nonexistent_share_instance(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.force_delete,
"fake",
s_type="share_instances")
@test.attr(type=["gate", "negative", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_force_delete_nonexistent_snapshot(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.force_delete,
"fake",
s_type="snapshots")
@test.attr(type=["gate", "negative", ])
def test_try_force_delete_share_with_member(self):
# If a non-admin tries to do force_delete, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.force_delete,
self.sh["id"])
@test.attr(type=["gate", "negative", ])
def test_try_force_delete_share_instance_with_member(self):
# If a non-admin tries to do force_delete, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.force_delete,
self.sh_instance["id"], s_type="share_instances")
@test.attr(type=["gate", "negative", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_try_force_delete_snapshot_with_member(self):
# If a non-admin tries to do force_delete, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.force_delete,
self.sn["id"], s_type="snapshots")
@test.attr(type=["gate", "negative", ])
def test_try_get_share_instance_with_member(self):
# If a non-admin tries to get instance, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.get_share_instance,
self.sh_instance["id"])
@test.attr(type=["gate", "negative", ])
def test_try_list_share_instance_with_member(self):
# If a non-admin tries to list instances, it should be unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.list_share_instances)
@test.attr(type=["gate", "negative", ])
def test_try_get_instances_of_share_with_member(self):
# If a non-admin tries to list instances of given share, it should be
# unauthorized
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.get_instances_of_share,
self.sh['id'])

View File

@ -0,0 +1,101 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib.common.utils import data_utils # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class ShareMultiBackendTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareMultiBackendTest, cls).resource_setup()
if not CONF.share.multi_backend:
raise cls.skipException("Manila multi-backend tests are disabled.")
elif len(CONF.share.backend_names) < 2:
raise cls.skipException("For running multi-backend tests required"
" two names in config. Skipping.")
elif any(not name for name in CONF.share.backend_names):
raise cls.skipException("Share backend names can not be empty. "
"Skipping.")
cls.sts = []
cls.shares = []
share_data_list = []
# Create share types
for i in [0, 1]:
st_name = data_utils.rand_name("share-type-%s" % str(i))
extra_specs = {
"share_backend_name": CONF.share.backend_names[i],
}
st = cls.create_share_type(
name=st_name,
extra_specs=cls.add_required_extra_specs_to_dict(extra_specs))
cls.sts.append(st["share_type"])
st_id = st["share_type"]["id"]
share_data_list.append({"kwargs": {"share_type_id": st_id}})
# Create shares using precreated share types
cls.shares = cls.create_shares(share_data_list)
@test.attr(type=["gate", "smoke", ])
def test_share_backend_name_reporting(self):
# Share's 'host' should be like "hostname@backend_name"
for share in self.shares:
get = self.shares_client.get_share(share['id'])
self.assertTrue(len(get["host"].split("@")) == 2)
@test.attr(type=["gate", "smoke", ])
def test_share_share_type(self):
# Share type should be the same as provided with share creation
for i in [0, 1]:
get = self.shares_client.get_share(self.shares[i]['id'])
self.assertEqual(get["share_type"], self.sts[i]["name"])
@test.attr(type=["gate", ])
def test_share_export_locations(self):
# Different backends have different IPs on interfaces
# and export locations should be different too.
if CONF.share.backend_names[0] == CONF.share.backend_names[1]:
raise self.skipException("Share backends "
"configured with same name. Skipping.")
ips = []
for share in self.shares:
get = self.shares_client.get_share(share['id'])
if get["share_proto"].lower() == "nfs":
# %ip%:/%share_path%
ip = get["export_location"].split(":")[0]
ips.append(ip)
elif get["share_proto"].lower() == "cifs":
# //%ip%/%share_path%
ip = get["export_location"][2:].split("/")[0]
ips.append(ip)
self.assertNotEqual(ips[0], ips[1])
@test.attr(type=["gate", ])
def test_share_backend_name_distinction(self):
# Different share backends should have different host records
if CONF.share.backend_names[0] == CONF.share.backend_names[1]:
raise self.skipException("Share backends "
"configured with same name. Skipping.")
get1 = self.shares_client.get_share(self.shares[0]['id'])
get2 = self.shares_client.get_share(self.shares[1]['id'])
self.assertNotEqual(get1["host"], get2["host"])

View File

@ -0,0 +1,351 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from manila_tempest_tests import clients_share as clients
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class SharesAdminQuotasTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
cls.os = clients.AdminManager()
super(SharesAdminQuotasTest, cls).resource_setup()
cls.user_id = cls.shares_client.user_id
cls.tenant_id = cls.shares_client.tenant_id
@test.attr(type=["gate", "smoke", ])
def test_default_quotas(self):
quotas = self.shares_client.default_quotas(self.tenant_id)
self.assertGreater(int(quotas["gigabytes"]), -2)
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
self.assertGreater(int(quotas["shares"]), -2)
self.assertGreater(int(quotas["snapshots"]), -2)
self.assertGreater(int(quotas["share_networks"]), -2)
@test.attr(type=["gate", "smoke", ])
def test_show_quotas(self):
quotas = self.shares_client.show_quotas(self.tenant_id)
self.assertGreater(int(quotas["gigabytes"]), -2)
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
self.assertGreater(int(quotas["shares"]), -2)
self.assertGreater(int(quotas["snapshots"]), -2)
self.assertGreater(int(quotas["share_networks"]), -2)
@test.attr(type=["gate", "smoke", ])
def test_show_quotas_for_user(self):
quotas = self.shares_client.show_quotas(self.tenant_id, self.user_id)
self.assertGreater(int(quotas["gigabytes"]), -2)
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
self.assertGreater(int(quotas["shares"]), -2)
self.assertGreater(int(quotas["snapshots"]), -2)
self.assertGreater(int(quotas["share_networks"]), -2)
class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
force_tenant_isolation = True
@test.attr(type=["gate", "smoke", ])
def test_update_tenant_quota_shares(self):
client = self.get_client_with_isolated_creds()
# get current quotas
quotas = client.show_quotas(client.tenant_id)
new_quota = int(quotas["shares"]) + 2
# set new quota for shares
updated = client.update_quotas(client.tenant_id, shares=new_quota)
self.assertEqual(int(updated["shares"]), new_quota)
@test.attr(type=["gate", "smoke", ])
def test_update_user_quota_shares(self):
client = self.get_client_with_isolated_creds()
# get current quotas
quotas = client.show_quotas(client.tenant_id, client.user_id)
new_quota = int(quotas["shares"]) - 1
# set new quota for shares
updated = client.update_quotas(
client.tenant_id, client.user_id, shares=new_quota)
self.assertEqual(int(updated["shares"]), new_quota)
@test.attr(type=["gate", "smoke", ])
def test_update_tenant_quota_snapshots(self):
client = self.get_client_with_isolated_creds()
# get current quotas
quotas = client.show_quotas(client.tenant_id)
new_quota = int(quotas["snapshots"]) + 2
# set new quota for snapshots
updated = client.update_quotas(client.tenant_id, snapshots=new_quota)
self.assertEqual(int(updated["snapshots"]), new_quota)
@test.attr(type=["gate", "smoke", ])
def test_update_user_quota_snapshots(self):
client = self.get_client_with_isolated_creds()
# get current quotas
quotas = client.show_quotas(client.tenant_id, client.user_id)
new_quota = int(quotas["snapshots"]) - 1
# set new quota for snapshots
updated = client.update_quotas(
client.tenant_id, client.user_id, snapshots=new_quota)
self.assertEqual(int(updated["snapshots"]), new_quota)
@test.attr(type=["gate", "smoke", ])
def test_update_tenant_quota_gigabytes(self):
client = self.get_client_with_isolated_creds()
# get current quotas
custom = client.show_quotas(client.tenant_id)
# make quotas for update
gigabytes = int(custom["gigabytes"]) + 2
# set new quota for shares
updated = client.update_quotas(
client.tenant_id, gigabytes=gigabytes)
self.assertEqual(int(updated["gigabytes"]), gigabytes)
@test.attr(type=["gate", "smoke", ])
def test_update_tenant_quota_snapshot_gigabytes(self):
client = self.get_client_with_isolated_creds()
# get current quotas
custom = client.show_quotas(client.tenant_id)
# make quotas for update
snapshot_gigabytes = int(custom["snapshot_gigabytes"]) + 2
# set new quota for shares
updated = client.update_quotas(
client.tenant_id,
snapshot_gigabytes=snapshot_gigabytes)
self.assertEqual(
int(updated["snapshot_gigabytes"]), snapshot_gigabytes)
@test.attr(type=["gate", "smoke", ])
def test_update_user_quota_gigabytes(self):
client = self.get_client_with_isolated_creds()
# get current quotas
custom = client.show_quotas(client.tenant_id, client.user_id)
# make quotas for update
gigabytes = int(custom["gigabytes"]) - 1
# set new quota for shares
updated = client.update_quotas(
client.tenant_id, client.user_id,
gigabytes=gigabytes)
self.assertEqual(int(updated["gigabytes"]), gigabytes)
@test.attr(type=["gate", "smoke", ])
def test_update_user_quota_snapshot_gigabytes(self):
client = self.get_client_with_isolated_creds()
# get current quotas
custom = client.show_quotas(client.tenant_id, client.user_id)
# make quotas for update
snapshot_gigabytes = int(custom["snapshot_gigabytes"]) - 1
# set new quota for shares
updated = client.update_quotas(
client.tenant_id, client.user_id,
snapshot_gigabytes=snapshot_gigabytes)
self.assertEqual(
int(updated["snapshot_gigabytes"]), snapshot_gigabytes)
@test.attr(type=["gate", "smoke", ])
def test_update_tenant_quota_share_networks(self):
client = self.get_client_with_isolated_creds()
# get current quotas
quotas = client.show_quotas(client.tenant_id)
new_quota = int(quotas["share_networks"]) + 2
# set new quota for share-networks
updated = client.update_quotas(
client.tenant_id, share_networks=new_quota)
self.assertEqual(int(updated["share_networks"]), new_quota)
@test.attr(type=["gate", "smoke", ])
def test_update_user_quota_share_networks(self):
client = self.get_client_with_isolated_creds()
# get current quotas
quotas = client.show_quotas(
client.tenant_id, client.user_id)
new_quota = int(quotas["share_networks"]) - 1
# set new quota for share-networks
updated = client.update_quotas(
client.tenant_id, client.user_id,
share_networks=new_quota)
self.assertEqual(int(updated["share_networks"]), new_quota)
@test.attr(type=["gate", "smoke", ])
def test_reset_tenant_quotas(self):
client = self.get_client_with_isolated_creds()
# get default_quotas
default = client.default_quotas(client.tenant_id)
# get current quotas
custom = client.show_quotas(client.tenant_id)
# make quotas for update
shares = int(custom["shares"]) + 2
snapshots = int(custom["snapshots"]) + 2
gigabytes = int(custom["gigabytes"]) + 2
snapshot_gigabytes = int(custom["snapshot_gigabytes"]) + 2
share_networks = int(custom["share_networks"]) + 2
# set new quota
updated = client.update_quotas(
client.tenant_id,
shares=shares,
snapshots=snapshots,
gigabytes=gigabytes,
snapshot_gigabytes=snapshot_gigabytes,
share_networks=share_networks)
self.assertEqual(int(updated["shares"]), shares)
self.assertEqual(int(updated["snapshots"]), snapshots)
self.assertEqual(int(updated["gigabytes"]), gigabytes)
self.assertEqual(
int(updated["snapshot_gigabytes"]), snapshot_gigabytes)
self.assertEqual(int(updated["share_networks"]), share_networks)
# reset customized quotas
client.reset_quotas(client.tenant_id)
# verify quotas
reseted = client.show_quotas(client.tenant_id)
self.assertEqual(int(reseted["shares"]), int(default["shares"]))
self.assertEqual(int(reseted["snapshots"]), int(default["snapshots"]))
self.assertEqual(int(reseted["gigabytes"]), int(default["gigabytes"]))
self.assertEqual(int(reseted["share_networks"]),
int(default["share_networks"]))
@test.attr(type=["gate", "smoke", ])
def test_unlimited_quota_for_shares(self):
client = self.get_client_with_isolated_creds()
client.update_quotas(client.tenant_id, shares=-1)
quotas = client.show_quotas(client.tenant_id)
self.assertEqual(-1, quotas.get('shares'))
@test.attr(type=["gate", "smoke", ])
def test_unlimited_user_quota_for_shares(self):
client = self.get_client_with_isolated_creds()
client.update_quotas(
client.tenant_id, client.user_id,
shares=-1)
quotas = client.show_quotas(client.tenant_id, client.user_id)
self.assertEqual(-1, quotas.get('shares'))
@test.attr(type=["gate", "smoke", ])
def test_unlimited_quota_for_snapshots(self):
client = self.get_client_with_isolated_creds()
client.update_quotas(client.tenant_id, snapshots=-1)
quotas = client.show_quotas(client.tenant_id)
self.assertEqual(-1, quotas.get('snapshots'))
@test.attr(type=["gate", "smoke", ])
def test_unlimited_user_quota_for_snapshots(self):
client = self.get_client_with_isolated_creds()
client.update_quotas(
client.tenant_id, client.user_id,
snapshots=-1)
quotas = client.show_quotas(client.tenant_id, client.user_id)
self.assertEqual(-1, quotas.get('snapshots'))
@test.attr(type=["gate", "smoke", ])
def test_unlimited_quota_for_gigabytes(self):
client = self.get_client_with_isolated_creds()
client.update_quotas(client.tenant_id, gigabytes=-1)
quotas = client.show_quotas(client.tenant_id)
self.assertEqual(-1, quotas.get('gigabytes'))
@test.attr(type=["gate", "smoke", ])
def test_unlimited_quota_for_snapshot_gigabytes(self):
client = self.get_client_with_isolated_creds()
client.update_quotas(
client.tenant_id, snapshot_gigabytes=-1)
quotas = client.show_quotas(client.tenant_id)
self.assertEqual(-1, quotas.get('snapshot_gigabytes'))
@test.attr(type=["gate", "smoke", ])
def test_unlimited_user_quota_for_gigabytes(self):
client = self.get_client_with_isolated_creds()
client.update_quotas(
client.tenant_id, client.user_id,
gigabytes=-1)
quotas = client.show_quotas(client.tenant_id, client.user_id)
self.assertEqual(-1, quotas.get('gigabytes'))
@test.attr(type=["gate", "smoke", ])
def test_unlimited_user_quota_for_snapshot_gigabytes(self):
client = self.get_client_with_isolated_creds()
client.update_quotas(
client.tenant_id, client.user_id,
snapshot_gigabytes=-1)
quotas = client.show_quotas(client.tenant_id, client.user_id)
self.assertEqual(-1, quotas.get('snapshot_gigabytes'))
@test.attr(type=["gate", "smoke", ])
def test_unlimited_quota_for_share_networks(self):
client = self.get_client_with_isolated_creds()
client.update_quotas(client.tenant_id, share_networks=-1)
quotas = client.show_quotas(client.tenant_id)
self.assertEqual(-1, quotas.get('share_networks'))
@test.attr(type=["gate", "smoke", ])
def test_unlimited_user_quota_for_share_networks(self):
client = self.get_client_with_isolated_creds()
client.update_quotas(
client.tenant_id, client.user_id,
share_networks=-1)
quotas = client.show_quotas(client.tenant_id, client.user_id)
self.assertEqual(-1, quotas.get('share_networks'))

View File

@ -0,0 +1,178 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests import clients_share as clients
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest):
force_tenant_isolation = True
@classmethod
def resource_setup(cls):
cls.os = clients.AdminManager()
super(SharesAdminQuotasNegativeTest, cls).resource_setup()
cls.user_id = cls.shares_client.user_id
cls.tenant_id = cls.shares_client.tenant_id
@test.attr(type=["gate", "smoke", "negative"])
def test_get_quotas_with_empty_tenant_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.show_quotas, "")
@test.attr(type=["gate", "smoke", "negative"])
def test_reset_quotas_with_empty_tenant_id(self):
client = self.get_client_with_isolated_creds()
self.assertRaises(lib_exc.NotFound,
client.reset_quotas, "")
@test.attr(type=["gate", "smoke", "negative"])
def test_update_shares_quota_with_wrong_data(self):
# -1 is acceptable value as unlimited
client = self.get_client_with_isolated_creds()
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
shares=-2)
@test.attr(type=["gate", "smoke", "negative"])
def test_update_snapshots_quota_with_wrong_data(self):
# -1 is acceptable value as unlimited
client = self.get_client_with_isolated_creds()
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
snapshots=-2)
@test.attr(type=["gate", "smoke", "negative"])
def test_update_gigabytes_quota_with_wrong_data(self):
# -1 is acceptable value as unlimited
client = self.get_client_with_isolated_creds()
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
gigabytes=-2)
@test.attr(type=["gate", "smoke", "negative"])
def test_update_snapshot_gigabytes_quota_with_wrong_data(self):
# -1 is acceptable value as unlimited
client = self.get_client_with_isolated_creds()
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
snapshot_gigabytes=-2)
@test.attr(type=["gate", "smoke", "negative"])
def test_update_share_networks_quota_with_wrong_data(self):
# -1 is acceptable value as unlimited
client = self.get_client_with_isolated_creds()
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
share_networks=-2)
@test.attr(type=["gate", "smoke", "negative"])
def test_create_share_with_size_bigger_than_quota(self):
quotas = self.shares_client.show_quotas(
self.shares_client.tenant_id)
overquota = int(quotas['gigabytes']) + 2
# try schedule share with size, bigger than gigabytes quota
self.assertRaises(lib_exc.OverLimit,
self.shares_client.create_share,
size=overquota)
@test.attr(type=["gate", "smoke", "negative"])
def test_try_set_user_quota_shares_bigger_than_tenant_quota(self):
client = self.get_client_with_isolated_creds()
# get current quotas for tenant
tenant_quotas = client.show_quotas(client.tenant_id)
# try set user quota for shares bigger than tenant quota
bigger_value = int(tenant_quotas["shares"]) + 2
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
client.user_id,
shares=bigger_value)
@test.attr(type=["gate", "smoke", "negative"])
def test_try_set_user_quota_snaps_bigger_than_tenant_quota(self):
client = self.get_client_with_isolated_creds()
# get current quotas for tenant
tenant_quotas = client.show_quotas(client.tenant_id)
# try set user quota for snapshots bigger than tenant quota
bigger_value = int(tenant_quotas["snapshots"]) + 2
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
client.user_id,
snapshots=bigger_value)
@test.attr(type=["gate", "smoke", "negative"])
def test_try_set_user_quota_gigabytes_bigger_than_tenant_quota(self):
client = self.get_client_with_isolated_creds()
# get current quotas for tenant
tenant_quotas = client.show_quotas(client.tenant_id)
# try set user quota for gigabytes bigger than tenant quota
bigger_value = int(tenant_quotas["gigabytes"]) + 2
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
client.user_id,
gigabytes=bigger_value)
@test.attr(type=["gate", "smoke", "negative"])
def test_try_set_user_quota_snap_gigabytes_bigger_than_tenant_quota(self):
client = self.get_client_with_isolated_creds()
# get current quotas for tenant
tenant_quotas = client.show_quotas(client.tenant_id)
# try set user quota for snapshot gigabytes bigger than tenant quota
bigger_value = int(tenant_quotas["snapshot_gigabytes"]) + 2
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
client.user_id,
snapshot_gigabytes=bigger_value)
@test.attr(type=["gate", "smoke", "negative"])
def test_try_set_user_quota_share_networks_bigger_than_tenant_quota(self):
client = self.get_client_with_isolated_creds()
# get current quotas for tenant
tenant_quotas = client.show_quotas(client.tenant_id)
# try set user quota for share_networks bigger than tenant quota
bigger_value = int(tenant_quotas["share_networks"]) + 2
self.assertRaises(lib_exc.BadRequest,
client.update_quotas,
client.tenant_id,
client.user_id,
share_networks=bigger_value)

View File

@ -0,0 +1,140 @@
# Copyright (c) 2015 Clinton Knight. 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 # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class SchedulerStatsAdminTest(base.BaseSharesAdminTest):
@test.attr(type=["gate", "smoke", ])
def test_pool_list(self):
# List pools
pool_response = self.shares_client.list_pools()
pool_list = pool_response.get('pools')
self.assertIsNotNone(pool_list, 'No pools returned from pools API')
self.assertNotEmpty(pool_list)
pool = pool_list[0]
required_keys = {'name', 'host', 'backend', 'pool'}
actual_keys = set(pool.keys())
self.assertTrue(actual_keys.issuperset(required_keys))
@test.attr(type=["gate", "smoke", ])
def test_pool_list_with_filters(self):
# List pools
pool_response = self.shares_client.list_pools()
pool_list = pool_response.get('pools')
# Ensure we got at least one pool
self.assertIsNotNone(pool_list, 'No pools returned from pools API')
self.assertNotEmpty(pool_list)
pool = pool_list[0]
# Build search opts from data and get pools again with filter
search_opts = {
'host': pool.get('host'),
'backend': pool.get('backend'),
'pool': pool.get('pool'),
}
pool_response = self.shares_client.list_pools(
search_opts=search_opts)
filtered_pool_list = pool_response.get('pools')
# Ensure we got exactly one pool matching the first one from above
self.assertEqual(1, len(filtered_pool_list))
# Match the key values, not the timestamp.
for k, v in search_opts.items():
self.assertEqual(v, filtered_pool_list[0][k])
@test.attr(type=["gate", "smoke", ])
def test_pool_list_with_filters_negative(self):
# Build search opts for a non-existent pool
search_opts = {
'host': 'foo',
'backend': 'bar',
'pool': 'shark',
}
pool_response = self.shares_client.list_pools(
search_opts=search_opts)
pool_list = pool_response.get('pools')
# Ensure we got no pools
self.assertEmpty(pool_list)
@test.attr(type=["gate", "smoke", ])
def test_pool_list_detail(self):
# List pools
pool_response = self.shares_client.list_pools(detail=True)
pool_list = pool_response.get('pools')
self.assertIsNotNone(pool_list, 'No pools returned from pools API')
self.assertNotEmpty(pool_list)
pool = pool_list[0]
required_keys = {'name', 'host', 'backend', 'pool', 'capabilities'}
actual_keys = set(pool.keys())
self.assertTrue(actual_keys.issuperset(required_keys))
@test.attr(type=["gate", "smoke", ])
def test_pool_list_detail_with_filters(self):
# List pools
pool_response = self.shares_client.list_pools(detail=True)
pool_list = pool_response.get('pools')
# Ensure we got at least one pool
self.assertIsNotNone(pool_list, 'No pools returned from pools API')
self.assertNotEmpty(pool_list)
pool = pool_list[0]
# Build search opts from data and get pools again with filter
search_opts = {
'host': pool.get('host'),
'backend': pool.get('backend'),
'pool': pool.get('pool'),
}
pool_response = self.shares_client.list_pools(
detail=True, search_opts=search_opts)
filtered_pool_list = pool_response.get('pools')
# Ensure we got exactly one pool matching the first one from above
self.assertEqual(1, len(filtered_pool_list))
# Match the key values, not the timestamp.
for k, v in search_opts.items():
self.assertEqual(v, filtered_pool_list[0][k])
@test.attr(type=["gate", "smoke", ])
def test_pool_list_detail_with_filters_negative(self):
# Build search opts for a non-existent pool
search_opts = {
'host': 'foo',
'backend': 'bar',
'pool': 'shark',
}
pool_response = self.shares_client.list_pools(
detail=True, search_opts=search_opts)
pool_list = pool_response.get('pools')
# Ensure we got no pools
self.assertEmpty(pool_list)

View File

@ -0,0 +1,64 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from manila_tempest_tests.tests.api import base
from manila_tempest_tests.tests.api import test_security_services
class SecurityServiceAdminTest(
base.BaseSharesAdminTest,
test_security_services.SecurityServiceListMixin):
def setUp(self):
super(SecurityServiceAdminTest, self).setUp()
ss_ldap_data = {
'name': 'ss_ldap',
'dns_ip': '1.1.1.1',
'server': 'fake_server_1',
'domain': 'fake_domain_1',
'user': 'fake_user',
'password': 'pass',
}
ss_kerberos_data = {
'name': 'ss_kerberos',
'dns_ip': '2.2.2.2',
'server': 'fake_server_2',
'domain': 'fake_domain_2',
'user': 'test_user',
'password': 'word',
}
self.ss_ldap = self.create_security_service('ldap', **ss_ldap_data)
self.ss_kerberos = self.create_security_service(
'kerberos',
**ss_kerberos_data)
@test.attr(type=["gate", "smoke", ])
def test_list_security_services_all_tenants(self):
listed = self.shares_client.list_security_services(
params={'all_tenants': 1})
self.assertTrue(any(self.ss_ldap['id'] == ss['id'] for ss in listed))
self.assertTrue(any(self.ss_kerberos['id'] == ss['id']
for ss in listed))
keys = ["name", "id", "status", "type", ]
[self.assertIn(key, s_s.keys()) for s_s in listed for key in keys]
@test.attr(type=["gate", "smoke", ])
def test_list_security_services_invalid_filters(self):
listed = self.shares_client.list_security_services(
params={'fake_opt': 'some_value'})
self.assertEqual(0, len(listed))

View File

@ -0,0 +1,96 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from manila_tempest_tests.tests.api import base
class ServicesAdminTest(base.BaseSharesAdminTest):
def setUp(self):
super(ServicesAdminTest, self).setUp()
self.services = self.shares_client.list_services()
@test.attr(type=["gate", "smoke", ])
def test_list_services(self):
services = self.shares_client.list_services()
self.assertNotEqual(0, len(services))
for service in services:
self.assertIsNotNone(service['id'])
@test.attr(type=["gate", "smoke", ])
def test_get_services_by_host_name(self):
host = self.services[0]["host"]
params = {"host": host}
services = self.shares_client.list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(host, service["host"])
@test.attr(type=["gate", "smoke", ])
def test_get_services_by_binary_name(self):
binary = self.services[0]["binary"]
params = {"binary": binary, }
services = self.shares_client.list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(binary, service["binary"])
@test.attr(type=["gate", "smoke", ])
def test_get_services_by_availability_zone(self):
zone = self.services[0]["zone"]
params = {"zone": zone, }
services = self.shares_client.list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(zone, service["zone"])
@test.attr(type=["gate", "smoke", ])
def test_get_services_by_status(self):
status = self.services[0]["status"]
params = {"status": status, }
services = self.shares_client.list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(status, service["status"])
@test.attr(type=["gate", "smoke", ])
def test_get_services_by_state(self):
state = self.services[0]["state"]
params = {"state": state, }
services = self.shares_client.list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(state, service["state"])
@test.attr(type=["gate", "smoke", ])
def test_get_services_by_all_filters(self):
params = {
"host": self.services[0]["host"],
"binary": self.services[0]["binary"],
"zone": self.services[0]["zone"],
"status": self.services[0]["status"],
"state": self.services[0]["state"],
}
services = self.shares_client.list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(params["host"], service["host"])
self.assertEqual(params["binary"], service["binary"])
self.assertEqual(params["zone"], service["zone"])
self.assertEqual(params["status"], service["status"])
self.assertEqual(params["state"], service["state"])

View File

@ -0,0 +1,78 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
from manila_tempest_tests import clients_share as clients
from manila_tempest_tests.tests.api import base
class ServicesAdminNegativeTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ServicesAdminNegativeTest, cls).resource_setup()
user_clients = clients.Manager()
cls.user_shares_client = user_clients.shares_client
@test.attr(type=["gate", "smoke", "negative", ])
def test_list_services_with_non_admin_user(self):
self.assertRaises(lib_exc.Forbidden,
self.user_shares_client.list_services)
@test.attr(type=["gate", "smoke", "negative", ])
def test_get_service_by_invalid_params(self):
# All services are expected if send the request with invalid parameter
services = self.shares_client.list_services()
params = {'fake_param': 'fake_param_value'}
services_fake = self.shares_client.list_services(params)
self.assertEqual(len(services), len(services_fake))
# "update_at" field could be updated before second request,
# so do not take it in account.
for service in services + services_fake:
service["updated_at"] = "removed_possible_difference"
self.assertEqual(services, services_fake)
@test.attr(type=["gate", "smoke", "negative", ])
def test_get_service_by_invalid_host(self):
params = {'host': 'fake_host'}
services_fake = self.shares_client.list_services(params)
self.assertEqual(0, len(services_fake))
@test.attr(type=["gate", "smoke", "negative", ])
def test_get_service_by_invalid_binary(self):
params = {'binary': 'fake_binary'}
services_fake = self.shares_client.list_services(params)
self.assertEqual(0, len(services_fake))
@test.attr(type=["gate", "smoke", "negative", ])
def test_get_service_by_invalid_zone(self):
params = {'zone': 'fake_zone'}
services_fake = self.shares_client.list_services(params)
self.assertEqual(0, len(services_fake))
@test.attr(type=["gate", "smoke", "negative", ])
def test_get_service_by_invalid_status(self):
params = {'status': 'fake_status'}
services_fake = self.shares_client.list_services(params)
self.assertEqual(0, len(services_fake))
@test.attr(type=["gate", "smoke", "negative", ])
def test_get_service_by_invalid_state(self):
params = {'state': 'fake_state'}
services_fake = self.shares_client.list_services(params)
self.assertEqual(0, len(services_fake))

View File

@ -0,0 +1,163 @@
# Copyright 2015 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib.common.utils import data_utils # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class ManageNFSShareTest(base.BaseSharesAdminTest):
protocol = 'nfs'
# NOTE(vponomaryov): be careful running these tests using generic driver
# because cinder volumes will stay attached to service Nova VM and
# won't be deleted.
@classmethod
@testtools.skipIf(
CONF.share.multitenancy_enabled,
"Only for driver_handles_share_servers = False driver mode.")
@testtools.skipUnless(
CONF.share.run_manage_unmanage_tests,
"Manage/unmanage tests are disabled.")
def resource_setup(cls):
super(ManageNFSShareTest, cls).resource_setup()
if cls.protocol not in CONF.share.enable_protocols:
message = "%s tests are disabled" % cls.protocol
raise cls.skipException(message)
# Create share types
cls.st_name = data_utils.rand_name("manage-st-name")
cls.st_name_invalid = data_utils.rand_name("manage-st-name-invalid")
cls.extra_specs = {
'storage_protocol': CONF.share.storage_protocol,
'driver_handles_share_servers': False
}
cls.extra_specs_invalid = {
'storage_protocol': CONF.share.storage_protocol,
'driver_handles_share_servers': True
}
cls.st = cls.create_share_type(
name=cls.st_name,
cleanup_in_class=True,
extra_specs=cls.extra_specs)
cls.st_invalid = cls.create_share_type(
name=cls.st_name_invalid,
cleanup_in_class=True,
extra_specs=cls.extra_specs_invalid)
creation_data = {'kwargs': {
'share_type_id': cls.st['share_type']['id'],
'share_protocol': cls.protocol,
}}
# Create two shares in parallel
cls.shares = cls.create_shares([creation_data, creation_data])
# Load all share data (host, etc.)
cls.share1 = cls.shares_client.get_share(cls.shares[0]['id'])
cls.share2 = cls.shares_client.get_share(cls.shares[1]['id'])
# Unmanage shares from manila
cls.shares_client.unmanage_share(cls.share1['id'])
cls.shares_client.wait_for_resource_deletion(share_id=cls.share1['id'])
cls.shares_client.unmanage_share(cls.share2['id'])
cls.shares_client.wait_for_resource_deletion(share_id=cls.share2['id'])
@test.attr(type=["gate", "smoke"])
def test_manage(self):
name = "Name for 'managed' share that had ID %s" % self.share1["id"]
description = "Description for 'managed' share"
# Manage share
share = self.shares_client.manage_share(
service_host=self.share1['host'],
export_path=self.share1['export_locations'][0],
protocol=self.share1['share_proto'],
share_type_id=self.st['share_type']['id'],
name=name,
description=description,
)
# Add managed share to cleanup queue
self.method_resources.insert(
0, {'type': 'share_type', 'id': share['id'],
'client': self.shares_client})
# Wait for success
self.shares_client.wait_for_share_status(share['id'], 'available')
# Verify data of managed share
get = self.shares_client.get_share(share['id'])
self.assertEqual(name, get['name'])
self.assertEqual(description, get['description'])
self.assertEqual(self.share1['host'], get['host'])
self.assertEqual(self.share1['share_proto'], get['share_proto'])
self.assertEqual(self.st['share_type']['name'], get['share_type'])
# Delete share
self.shares_client.delete_share(share['id'])
self.shares_client.wait_for_resource_deletion(share_id=share['id'])
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share,
share['id'])
@test.attr(type=["gate", "smoke"])
def test_manage_retry(self):
# Manage share with invalid parameters
share = None
parameters = [(self.st_invalid['share_type']['id'], 'manage_error'),
(self.st['share_type']['id'], 'available')]
for share_type_id, status in parameters:
share = self.shares_client.manage_share(
service_host=self.share2['host'],
export_path=self.share2['export_locations'][0],
protocol=self.share2['share_proto'],
share_type_id=share_type_id)
# Add managed share to cleanup queue
self.method_resources.insert(
0, {'type': 'share_type', 'id': share['id'],
'client': self.shares_client})
# Wait for success
self.shares_client.wait_for_share_status(share['id'], status)
# Delete share
self.shares_client.delete_share(share['id'])
self.shares_client.wait_for_resource_deletion(share_id=share['id'])
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share,
share['id'])
class ManageCIFSShareTest(ManageNFSShareTest):
protocol = 'cifs'
class ManageGLUSTERFSShareTest(ManageNFSShareTest):
protocol = 'glusterfs'
class ManageHDFSShareTest(ManageNFSShareTest):
protocol = 'hdfs'

View File

@ -0,0 +1,97 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from manila_tempest_tests.tests.api import base
from manila_tempest_tests.tests.api import test_share_networks
class ShareNetworkAdminTest(
base.BaseSharesAdminTest,
test_share_networks.ShareNetworkListMixin):
@classmethod
def resource_setup(cls):
super(ShareNetworkAdminTest, cls).resource_setup()
ss_data = cls.generate_security_service_data()
cls.ss_ldap = cls.create_security_service(**ss_data)
cls.data_sn_with_ldap_ss = {
'name': 'sn_with_ldap_ss',
'neutron_net_id': '1111',
'neutron_subnet_id': '2222',
'created_at': '2002-02-02',
'updated_at': None,
'network_type': 'vlan',
'segmentation_id': 1000,
'cidr': '10.0.0.0/24',
'ip_version': 4,
'description': 'fake description',
}
cls.sn_with_ldap_ss = cls.create_share_network(
cleanup_in_class=True,
**cls.data_sn_with_ldap_ss)
cls.shares_client.add_sec_service_to_share_network(
cls.sn_with_ldap_ss["id"],
cls.ss_ldap["id"])
cls.isolated_client = cls.get_client_with_isolated_creds(
type_of_creds='alt')
cls.data_sn_with_kerberos_ss = {
'name': 'sn_with_kerberos_ss',
'neutron_net_id': '3333',
'neutron_subnet_id': '4444',
'created_at': '2003-03-03',
'updated_at': None,
'neutron_net_id': 'test net id',
'neutron_subnet_id': 'test subnet id',
'network_type': 'local',
'segmentation_id': 2000,
'cidr': '10.0.0.0/13',
'ip_version': 6,
'description': 'fake description',
}
cls.ss_kerberos = cls.isolated_client.create_security_service(
ss_type='kerberos',
**cls.data_sn_with_ldap_ss)
cls.sn_with_kerberos_ss = cls.isolated_client.create_share_network(
cleanup_in_class=True,
**cls.data_sn_with_kerberos_ss)
cls.isolated_client.add_sec_service_to_share_network(
cls.sn_with_kerberos_ss["id"],
cls.ss_kerberos["id"])
@test.attr(type=["gate", "smoke", ])
def test_list_share_networks_all_tenants(self):
listed = self.shares_client.list_share_networks_with_detail(
{'all_tenants': 1})
self.assertTrue(any(self.sn_with_ldap_ss['id'] == sn['id']
for sn in listed))
self.assertTrue(any(self.sn_with_kerberos_ss['id'] == sn['id']
for sn in listed))
@test.attr(type=["gate", "smoke", ])
def test_list_share_networks_filter_by_project_id(self):
listed = self.shares_client.list_share_networks_with_detail(
{'project_id': self.sn_with_kerberos_ss['project_id']})
self.assertTrue(any(self.sn_with_kerberos_ss['id'] == sn['id']
for sn in listed))
self.assertTrue(all(self.sn_with_kerberos_ss['project_id'] ==
sn['project_id'] for sn in listed))

View File

@ -0,0 +1,276 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import re
import six # noqa
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class ShareServersAdminTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareServersAdminTest, cls).resource_setup()
if not CONF.share.multitenancy_enabled:
msg = ("Share servers can be tested only with multitenant drivers."
" Skipping.")
raise cls.skipException(msg)
cls.share = cls.create_share()
cls.share_network = cls.shares_client.get_share_network(
cls.shares_client.share_network_id)
if not cls.share_network["name"]:
sn_id = cls.share_network["id"]
cls.share_network = cls.shares_client.update_share_network(
sn_id, name="sn_%s" % sn_id)
cls.sn_name_and_id = [
cls.share_network["name"],
cls.share_network["id"],
]
# Date should be like '2014-13-12T11:10:09.000000'
cls.date_re = re.compile("^([0-9]{4}-[0-9]{2}-[0-9]{2}[A-Z]{1}"
"[0-9]{2}:[0-9]{2}:[0-9]{2}).*$")
@test.attr(type=["gate", "smoke", ])
def test_list_share_servers_without_filters(self):
servers = self.shares_client.list_share_servers()
self.assertTrue(len(servers) > 0)
keys = [
"id",
"host",
"status",
"share_network_name",
"updated_at",
"project_id",
]
for server in servers:
# All expected keys are present
for key in keys:
self.assertIn(key, server.keys())
# 'Updated at' is valid date if set
if server["updated_at"]:
self.assertTrue(self.date_re.match(server["updated_at"]))
# Host is not empty
self.assertTrue(len(server["host"]) > 0)
# Id is not empty
self.assertTrue(len(server["id"]) > 0)
# Project id is not empty
self.assertTrue(len(server["project_id"]) > 0)
# Do not verify statuses because we get all share servers from whole
# cluster and here can be servers with any state.
# Server we used is present.
any(s["share_network_name"] in self.sn_name_and_id for s in servers)
@test.attr(type=["gate", "smoke", ])
def test_list_share_servers_with_host_filter(self):
# Get list of share servers and remember 'host' name
servers = self.shares_client.list_share_servers()
# Remember name of server that was used by this test suite
# to be sure it will be still existing.
host = ""
for server in servers:
if server["share_network_name"] in self.sn_name_and_id:
if not server["host"]:
msg = ("Server '%s' has wrong value for host - "
"'%s'.") % (server["id"], server["host"])
raise lib_exc.InvalidContentType(message=msg)
host = server["host"]
break
if not host:
msg = ("Appropriate server was not found. Its share_network_data"
": '%s'. List of servers: '%s'.") % (self.sn_name_and_id,
str(servers))
raise lib_exc.NotFound(message=msg)
search_opts = {"host": host}
servers = self.shares_client.list_share_servers(search_opts)
self.assertTrue(len(servers) > 0)
for server in servers:
self.assertEqual(server["host"], host)
@test.attr(type=["gate", "smoke", ])
def test_list_share_servers_with_status_filter(self):
# Get list of share servers
servers = self.shares_client.list_share_servers()
# Remember status of server that was used by this test suite
# to be sure it will be still existing.
status = ""
for server in servers:
if server["share_network_name"] in self.sn_name_and_id:
if not server["status"]:
msg = ("Server '%s' has wrong value for status - "
"'%s'.") % (server["id"], server["host"])
raise lib_exc.InvalidContentType(message=msg)
status = server["status"]
break
if not status:
msg = ("Appropriate server was not found. Its share_network_data"
": '%s'. List of servers: '%s'.") % (self.sn_name_and_id,
str(servers))
raise lib_exc.NotFound(message=msg)
search_opts = {"status": status}
servers = self.shares_client.list_share_servers(search_opts)
self.assertTrue(len(servers) > 0)
for server in servers:
self.assertEqual(server["status"], status)
@test.attr(type=["gate", "smoke", ])
def test_list_share_servers_with_project_id_filter(self):
search_opts = {"project_id": self.share_network["project_id"]}
servers = self.shares_client.list_share_servers(search_opts)
# Should exist, at least, one share server, used by this test suite.
self.assertTrue(len(servers) > 0)
for server in servers:
self.assertEqual(server["project_id"],
self.share_network["project_id"])
@test.attr(type=["gate", "smoke", ])
def test_list_share_servers_with_share_network_name_filter(self):
search_opts = {"share_network": self.share_network["name"]}
servers = self.shares_client.list_share_servers(search_opts)
# Should exist, at least, one share server, used by this test suite.
self.assertTrue(len(servers) > 0)
for server in servers:
self.assertEqual(server["share_network_name"],
self.share_network["name"])
@test.attr(type=["gate", "smoke", ])
def test_list_share_servers_with_share_network_id_filter(self):
search_opts = {"share_network": self.share_network["id"]}
servers = self.shares_client.list_share_servers(search_opts)
# Should exist, at least, one share server, used by this test suite.
self.assertTrue(len(servers) > 0)
for server in servers:
self.assertIn(server["share_network_name"],
self.sn_name_and_id)
@test.attr(type=["gate", "smoke", ])
def test_show_share_server(self):
servers = self.shares_client.list_share_servers()
server = self.shares_client.show_share_server(servers[0]["id"])
keys = [
"id",
"host",
"project_id",
"status",
"share_network_name",
"created_at",
"updated_at",
"backend_details",
]
# all expected keys are present
for key in keys:
self.assertIn(key, server.keys())
# 'created_at' is valid date
self.assertTrue(self.date_re.match(server["created_at"]))
# 'updated_at' is valid date if set
if server["updated_at"]:
self.assertTrue(self.date_re.match(server["updated_at"]))
# Host is not empty
self.assertTrue(len(server["host"]) > 0)
# Id is not empty
self.assertTrue(len(server["id"]) > 0)
# Project id is not empty
self.assertTrue(len(server["project_id"]) > 0)
# Status is not empty
self.assertTrue(len(server["status"]) > 0)
# share_network_name is not empty
self.assertTrue(len(server["share_network_name"]) > 0)
# backend_details should be a dict
self.assertTrue(isinstance(server["backend_details"], dict))
@test.attr(type=["gate", "smoke", ])
def test_show_share_server_details(self):
servers = self.shares_client.list_share_servers()
details = self.shares_client.show_share_server_details(
servers[0]["id"])
# If details are present they and their values should be only strings
for k, v in details.iteritems():
self.assertTrue(isinstance(k, six.string_types))
self.assertTrue(isinstance(v, six.string_types))
@test.attr(type=["gate", "smoke", ])
def _delete_share_server(self, delete_share_network):
# Get network and subnet from existing share_network and reuse it
# to be able to delete share_server after test ends.
# TODO(vponomaryov): attach security-services too. If any exist from
# donor share-network.
new_sn = self.create_share_network(
neutron_net_id=self.share_network['neutron_net_id'],
neutron_subnet_id=self.share_network['neutron_subnet_id'])
# Create server with share
share = self.create_share(share_network_id=new_sn['id'])
# List share servers, filtered by share_network_id
search_opts = {"share_network": new_sn["id"]}
servers = self.shares_client.list_share_servers(search_opts)
# There can be more than one share server for share network when retry
# was used and share was created successfully not from first time.
# So, iterate all share-servers, release all created resources. It will
# allow share network to be deleted in cleanup.
for serv in servers:
# Verify that filtering worked as expected.
self.assertEqual(new_sn["id"], serv["share_network_id"])
# List shares by share server id
params = {"share_server_id": serv["id"]}
shares = self.shares_client.list_shares_with_detail(params)
for s in shares:
self.assertEqual(new_sn["id"], s["share_network_id"])
self.assertTrue(any(share["id"] == s["id"] for s in shares))
# Delete shares, so we will have share server without shares
for s in shares:
self.shares_client.delete_share(s["id"])
# Wait for shares deletion
for s in shares:
self.shares_client.wait_for_resource_deletion(share_id=s["id"])
# List shares by share server id, we expect empty list
params = {"share_server_id": serv["id"]}
empty = self.shares_client.list_shares_with_detail(params)
self.assertEqual(len(empty), 0)
if delete_share_network:
# Delete share network, it should trigger share server deletion
self.shares_client.delete_share_network(new_sn["id"])
else:
# Delete share server
self.shares_client.delete_share_server(serv["id"])
# Wait for share server deletion
self.shares_client.wait_for_resource_deletion(server_id=serv["id"])
if delete_share_network:
self.shares_client.wait_for_resource_deletion(
sn_id=new_sn["id"])
@test.attr(type=["gate", "smoke", ])
def test_delete_share_server(self):
self._delete_share_server(False)
@test.attr(type=["gate", "smoke", ])
def test_delete_share_server_by_deletion_of_share_network(self):
self._delete_share_server(True)

View File

@ -0,0 +1,108 @@
# Copyright 2014 OpenStack Foundation
# 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 test # noqa
from tempest_lib.common.utils import data_utils # noqa
from tempest_lib import exceptions as lib_exc # noqa
from manila_tempest_tests import clients_share as clients
from manila_tempest_tests.tests.api import base
class ShareServersNegativeAdminTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareServersNegativeAdminTest, cls).resource_setup()
cls.member_shares_client = clients.Manager().shares_client
@test.attr(type=["gate", "smoke", "negative", ])
def test_try_list_share_servers_with_member(self):
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.list_share_servers)
@test.attr(type=["gate", "smoke", "negative", ])
def test_try_show_share_server_with_member(self):
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.show_share_server,
'fake_id')
@test.attr(type=["gate", "smoke", "negative", ])
def test_try_show_share_server_details_with_member(self):
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.show_share_server_details,
'fake_id')
@test.attr(type=["gate", "smoke", "negative", ])
def test_show_share_server_with_inexistent_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.show_share_server,
'fake_id')
@test.attr(type=["gate", "smoke", "negative", ])
def test_show_share_server_details_with_inexistent_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.show_share_server_details,
'fake_id')
@test.attr(type=["gate", "smoke", "negative", ])
def test_list_share_servers_with_wrong_filter_key(self):
search_opts = {'fake_filter_key': 'ACTIVE'}
servers = self.shares_client.list_share_servers(search_opts)
self.assertEqual(len(servers), 0)
@test.attr(type=["gate", "smoke", "negative", ])
def test_list_share_servers_with_wrong_filter_value(self):
search_opts = {'host': 123}
servers = self.shares_client.list_share_servers(search_opts)
self.assertEqual(len(servers), 0)
@test.attr(type=["gate", "smoke", "negative", ])
def test_list_share_servers_with_fake_status(self):
search_opts = {"status": data_utils.rand_name("fake_status")}
servers = self.shares_client.list_share_servers(search_opts)
self.assertEqual(len(servers), 0)
@test.attr(type=["gate", "smoke", "negative", ])
def test_list_share_servers_with_fake_host(self):
search_opts = {"host": data_utils.rand_name("fake_host")}
servers = self.shares_client.list_share_servers(search_opts)
self.assertEqual(len(servers), 0)
@test.attr(type=["gate", "smoke", "negative", ])
def test_list_share_servers_with_fake_project(self):
search_opts = {"project_id": data_utils.rand_name("fake_project_id")}
servers = self.shares_client.list_share_servers(search_opts)
self.assertEqual(len(servers), 0)
@test.attr(type=["gate", "smoke", "negative", ])
def test_list_share_servers_with_fake_share_network(self):
search_opts = {
"share_network": data_utils.rand_name("fake_share_network"),
}
servers = self.shares_client.list_share_servers(search_opts)
self.assertEqual(len(servers), 0)
@test.attr(type=["gate", "smoke", "negative", ])
def test_delete_share_server_with_nonexistent_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_share_server,
"fake_nonexistent_share_server_id")
@test.attr(type=["gate", "smoke", "negative", ])
def test_delete_share_server_with_member(self):
self.assertRaises(lib_exc.Forbidden,
self.member_shares_client.delete_share_server,
"fake_nonexistent_share_server_id")

View File

@ -0,0 +1,160 @@
# Copyright 2014 OpenStack Foundation
# 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 # noqa
from tempest import test # noqa
from tempest_lib.common.utils import data_utils # noqa
from tempest_lib import exceptions as lib_exc # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class ShareTypesAdminTest(base.BaseSharesAdminTest):
@test.attr(type=["gate", "smoke", ])
def test_share_type_create_delete(self):
name = data_utils.rand_name("tempest-manila")
extra_specs = self.add_required_extra_specs_to_dict()
# Create share type
st_create = self.shares_client.create_share_type(
name, extra_specs=extra_specs)
self.assertEqual(name, st_create['share_type']['name'])
st_id = st_create['share_type']['id']
# Delete share type
self.shares_client.delete_share_type(st_id)
# Verify deletion of share type
self.shares_client.wait_for_resource_deletion(st_id=st_id)
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share_type,
st_id)
@test.attr(type=["gate", "smoke", ])
def test_share_type_create_get(self):
name = data_utils.rand_name("tempest-manila")
extra_specs = self.add_required_extra_specs_to_dict({"key": "value", })
# Create share type
st_create = self.create_share_type(name, extra_specs=extra_specs)
self.assertEqual(name, st_create['share_type']['name'])
st_id = st_create["share_type"]["id"]
# Get share type
get = self.shares_client.get_share_type(st_id)
self.assertEqual(name, get["share_type"]["name"])
self.assertEqual(st_id, get["share_type"]["id"])
self.assertEqual(extra_specs, get["share_type"]["extra_specs"])
# Check that backwards compatibility didn't break
self.assertDictMatch(get["volume_type"], get["share_type"])
@test.attr(type=["gate", "smoke", ])
def test_share_type_create_list(self):
name = data_utils.rand_name("tempest-manila")
extra_specs = self.add_required_extra_specs_to_dict()
# Create share type
st_create = self.create_share_type(name, extra_specs=extra_specs)
st_id = st_create["share_type"]["id"]
# list share types
st_list = self.shares_client.list_share_types()
sts = st_list["share_types"]
self.assertTrue(len(sts) >= 1)
self.assertTrue(any(st_id in st["id"] for st in sts))
# Check that backwards compatibility didn't break
vts = st_list["volume_types"]
self.assertEqual(len(sts), len(vts))
for i in xrange(len(sts)):
self.assertDictMatch(sts[i], vts[i])
@test.attr(type=["gate", "smoke", ])
def test_get_share_with_share_type(self):
# Data
share_name = data_utils.rand_name("share")
shr_type_name = data_utils.rand_name("share-type")
extra_specs = self.add_required_extra_specs_to_dict({
"storage_protocol": CONF.share.storage_protocol,
})
# Create share type
st_create = self.create_share_type(
shr_type_name, extra_specs=extra_specs)
# Create share with share type
share = self.create_share(
name=share_name, share_type_id=st_create["share_type"]["id"])
self.assertEqual(share["name"], share_name)
self.shares_client.wait_for_share_status(share["id"], "available")
# Verify share info
get = self.shares_client.get_share(share["id"])
self.assertEqual(share_name, get["name"])
self.assertEqual(share["id"], get["id"])
self.assertEqual(shr_type_name, get["share_type"])
def test_private_share_type_access(self):
name = data_utils.rand_name("tempest-manila")
extra_specs = self.add_required_extra_specs_to_dict({"key": "value", })
project_id = self.shares_client.tenant_id
# Create private share type
st_create = self.create_share_type(
name, False, extra_specs=extra_specs)
self.assertEqual(name, st_create['share_type']['name'])
st_id = st_create["share_type"]["id"]
# It should not be listed without access
st_list = self.shares_client.list_share_types()
sts = st_list["share_types"]
self.assertFalse(any(st_id in st["id"] for st in sts))
# List projects that have access for share type - none expected
access = self.shares_client.list_access_to_share_type(st_id)
self.assertEqual([], access)
# Add project access to share type
access = self.shares_client.add_access_to_share_type(
st_id, project_id)
# Now it should be listed
st_list = self.shares_client.list_share_types()
sts = st_list["share_types"]
self.assertTrue(any(st_id in st["id"] for st in sts))
# List projects that have access for share type - one expected
access = self.shares_client.list_access_to_share_type(st_id)
expected = [{'share_type_id': st_id, 'project_id': project_id}, ]
self.assertEqual(expected, access)
# Remove project access from share type
access = self.shares_client.remove_access_from_share_type(
st_id, project_id)
# It should not be listed without access
st_list = self.shares_client.list_share_types()
sts = st_list["share_types"]
self.assertFalse(any(st_id in st["id"] for st in sts))
# List projects that have access for share type - none expected
access = self.shares_client.list_access_to_share_type(st_id)
self.assertEqual([], access)

View File

@ -0,0 +1,111 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
from tempest import test # noqa
from tempest_lib.common.utils import data_utils # noqa
from manila_tempest_tests.tests.api import base
class ExtraSpecsReadAdminTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ExtraSpecsReadAdminTest, cls).resource_setup()
cls.share_type_name = data_utils.rand_name("share-type")
cls.required_extra_specs = cls.add_required_extra_specs_to_dict()
cls.share_type = cls.create_share_type(
cls.share_type_name, extra_specs=cls.required_extra_specs)
cls.st_id = cls.share_type["share_type"]["id"]
cls.custom_extra_specs = {"key1": "value1", "key2": "value2"}
cls.expected_extra_specs = copy.copy(cls.custom_extra_specs)
cls.expected_extra_specs.update(cls.required_extra_specs)
cls.shares_client.create_share_type_extra_specs(
cls.st_id, cls.custom_extra_specs)
@test.attr(type=["gate", "smoke", ])
def test_get_one_share_type_extra_spec(self):
es_get_one = self.shares_client.get_share_type_extra_spec(
self.st_id, "key1")
self.assertEqual({"key1": self.custom_extra_specs["key1"]}, es_get_one)
@test.attr(type=["gate", "smoke", ])
def test_get_all_share_type_extra_specs(self):
es_get_all = self.shares_client.get_share_type_extra_specs(self.st_id)
self.assertEqual(self.expected_extra_specs, es_get_all)
class ExtraSpecsWriteAdminTest(base.BaseSharesAdminTest):
def setUp(self):
super(ExtraSpecsWriteAdminTest, self).setUp()
self.required_extra_specs = self.add_required_extra_specs_to_dict()
self.custom_extra_specs = {"key1": "value1", "key2": "value2"}
self.share_type_name = data_utils.rand_name("share-type")
# Create share type
self.share_type = self.create_share_type(
self.share_type_name, extra_specs=self.required_extra_specs)
self.st_id = self.share_type['share_type']['id']
# Create extra specs for share type
self.shares_client.create_share_type_extra_specs(
self.st_id, self.custom_extra_specs)
@test.attr(type=["gate", "smoke", ])
def test_update_one_share_type_extra_spec(self):
self.custom_extra_specs["key1"] = "fake_value1_updated"
# Update extra specs of share type
update_one = self.shares_client.update_share_type_extra_spec(
self.st_id, "key1", self.custom_extra_specs["key1"])
self.assertEqual({"key1": self.custom_extra_specs["key1"]}, update_one)
get = self.shares_client.get_share_type_extra_specs(self.st_id)
expected_extra_specs = self.custom_extra_specs
expected_extra_specs.update(self.required_extra_specs)
self.assertEqual(self.custom_extra_specs, get)
@test.attr(type=["gate", "smoke", ])
def test_update_all_share_type_extra_specs(self):
self.custom_extra_specs["key2"] = "value2_updated"
# Update extra specs of share type
update_all = self.shares_client.update_share_type_extra_specs(
self.st_id, self.custom_extra_specs)
self.assertEqual(self.custom_extra_specs, update_all)
get = self.shares_client.get_share_type_extra_specs(self.st_id)
expected_extra_specs = self.custom_extra_specs
expected_extra_specs.update(self.required_extra_specs)
self.assertEqual(self.custom_extra_specs, get)
@test.attr(type=["gate", "smoke", ])
def test_delete_one_share_type_extra_spec(self):
# Delete one extra spec for share type
self.shares_client.delete_share_type_extra_spec(self.st_id, "key1")
# Get metadata
get = self.shares_client.get_share_type_extra_specs(self.st_id)
self.assertNotIn('key1', get)

View File

@ -0,0 +1,269 @@
# Copyright 2014 OpenStack Foundation
# 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 test # noqa
from tempest_lib.common.utils import data_utils # noqa
from tempest_lib import exceptions as lib_exc # noqa
from manila_tempest_tests import clients_share as clients
from manila_tempest_tests.tests.api import base
class ExtraSpecsAdminNegativeTest(base.BaseSharesAdminTest):
def _create_share_type(self):
name = data_utils.rand_name("unique_st_name")
extra_specs = self.add_required_extra_specs_to_dict({"key": "value"})
return self.create_share_type(name, extra_specs=extra_specs)
@classmethod
def resource_setup(cls):
super(ExtraSpecsAdminNegativeTest, cls).resource_setup()
cls.member_shares_client = clients.Manager().shares_client
@test.attr(type=["gate", "smoke", ])
def test_try_create_extra_specs_with_user(self):
st = self._create_share_type()
self.assertRaises(
lib_exc.Forbidden,
self.member_shares_client.create_share_type_extra_specs,
st["share_type"]["id"],
self.add_required_extra_specs_to_dict({"key": "new_value"}))
@test.attr(type=["gate", "smoke", ])
def test_try_list_extra_specs_with_user(self):
st = self._create_share_type()
self.assertRaises(
lib_exc.Forbidden,
self.member_shares_client.get_share_type_extra_specs,
st["share_type"]["id"])
@test.attr(type=["gate", "smoke", ])
def test_try_get_extra_spec_with_user(self):
st = self._create_share_type()
self.assertRaises(
lib_exc.Forbidden,
self.member_shares_client.get_share_type_extra_spec,
st["share_type"]["id"], "key")
@test.attr(type=["gate", "smoke", ])
def test_try_get_extra_specs_with_user(self):
st = self._create_share_type()
self.assertRaises(
lib_exc.Forbidden,
self.member_shares_client.get_share_type_extra_specs,
st["share_type"]["id"])
@test.attr(type=["gate", "smoke", ])
def test_try_update_extra_spec_with_user(self):
st = self._create_share_type()
self.assertRaises(
lib_exc.Forbidden,
self.member_shares_client.update_share_type_extra_spec,
st["share_type"]["id"], "key", "new_value")
@test.attr(type=["gate", "smoke", ])
def test_try_update_extra_specs_with_user(self):
st = self._create_share_type()
self.assertRaises(
lib_exc.Forbidden,
self.member_shares_client.update_share_type_extra_specs,
st["share_type"]["id"], {"key": "new_value"})
@test.attr(type=["gate", "smoke", ])
def test_try_delete_extra_specs_with_user(self):
st = self._create_share_type()
self.assertRaises(
lib_exc.Forbidden,
self.member_shares_client.delete_share_type_extra_spec,
st["share_type"]["id"], "key")
@test.attr(type=["gate", "smoke", ])
def test_try_set_too_long_key(self):
too_big_key = "k" * 256
st = self._create_share_type()
self.assertRaises(
lib_exc.BadRequest,
self.shares_client.create_share_type_extra_specs,
st["share_type"]["id"],
self.add_required_extra_specs_to_dict({too_big_key: "value"}))
@test.attr(type=["gate", "smoke", ])
def test_try_set_too_long_value_with_creation(self):
too_big_value = "v" * 256
st = self._create_share_type()
self.assertRaises(
lib_exc.BadRequest,
self.shares_client.create_share_type_extra_specs,
st["share_type"]["id"],
self.add_required_extra_specs_to_dict({"key": too_big_value}))
@test.attr(type=["gate", "smoke", ])
def test_try_set_too_long_value_with_update(self):
too_big_value = "v" * 256
st = self._create_share_type()
self.shares_client.create_share_type_extra_specs(
st["share_type"]["id"],
self.add_required_extra_specs_to_dict({"key": "value"}))
self.assertRaises(
lib_exc.BadRequest,
self.shares_client.update_share_type_extra_specs,
st["share_type"]["id"],
self.add_required_extra_specs_to_dict({"key": too_big_value}))
@test.attr(type=["gate", "smoke", ])
def test_try_set_too_long_value_with_update_of_one_key(self):
too_big_value = "v" * 256
st = self._create_share_type()
self.shares_client.create_share_type_extra_specs(
st["share_type"]["id"],
self.add_required_extra_specs_to_dict({"key": "value"}))
self.assertRaises(lib_exc.BadRequest,
self.shares_client.update_share_type_extra_spec,
st["share_type"]["id"], "key", too_big_value)
@test.attr(type=["gate", "smoke", ])
def test_try_list_es_with_empty_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share_type_extra_specs, "")
@test.attr(type=["gate", "smoke", ])
def test_try_list_es_with_invalid_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share_type_extra_specs,
data_utils.rand_name("fake"))
@test.attr(type=["gate", "smoke", ])
def test_try_create_es_with_empty_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.create_share_type_extra_specs,
"", {"key1": "value1", })
@test.attr(type=["gate", "smoke", ])
def test_try_create_es_with_invalid_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.create_share_type_extra_specs,
data_utils.rand_name("fake"), {"key1": "value1", })
@test.attr(type=["gate", "smoke", ])
def test_try_create_es_with_empty_specs(self):
st = self._create_share_type()
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_share_type_extra_specs,
st["share_type"]["id"], "")
@test.attr(type=["gate", "smoke", ])
def test_try_create_es_with_invalid_specs(self):
st = self._create_share_type()
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_share_type_extra_specs,
st["share_type"]["id"], {"": "value_with_empty_key"})
@test.attr(type=["gate", "smoke", ])
def test_try_get_extra_spec_with_empty_key(self):
st = self._create_share_type()
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share_type_extra_spec,
st["share_type"]["id"], "")
@test.attr(type=["gate", "smoke", ])
def test_try_get_extra_spec_with_invalid_key(self):
st = self._create_share_type()
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share_type_extra_spec,
st["share_type"]["id"], data_utils.rand_name("fake"))
@test.attr(type=["gate", "smoke", ])
def test_try_get_extra_specs_with_empty_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share_type_extra_specs,
"")
@test.attr(type=["gate", "smoke", ])
def test_try_get_extra_specs_with_invalid_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share_type_extra_specs,
data_utils.rand_name("fake"))
@test.attr(type=["gate", "smoke", ])
def test_try_delete_es_key_with_empty_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_share_type_extra_spec,
"", "key", )
@test.attr(type=["gate", "smoke", ])
def test_try_delete_es_key_with_invalid_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_share_type_extra_spec,
data_utils.rand_name("fake"), "key", )
@test.attr(type=["gate", "smoke", ])
def test_try_delete_with_invalid_key(self):
st = self._create_share_type()
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_share_type_extra_spec,
st["share_type"]["id"], data_utils.rand_name("fake"))
@test.attr(type=["gate", "smoke", ])
def test_try_update_spec_with_empty_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.update_share_type_extra_spec,
"", "key", "new_value")
@test.attr(type=["gate", "smoke", ])
def test_try_update_spec_with_invalid_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.update_share_type_extra_spec,
data_utils.rand_name("fake"), "key", "new_value")
@test.attr(type=["gate", "smoke", ])
def test_try_update_spec_with_empty_key(self):
st = self._create_share_type()
self.assertRaises(lib_exc.NotFound,
self.shares_client.update_share_type_extra_spec,
st["share_type"]["id"], "", "new_value")
@test.attr(type=["gate", "smoke", ])
def test_try_update_with_invalid_shr_type_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.update_share_type_extra_specs,
data_utils.rand_name("fake"), {"key": "new_value"})
@test.attr(type=["gate", "smoke", ])
def test_try_update_with_invalid_specs(self):
st = self._create_share_type()
self.assertRaises(lib_exc.BadRequest,
self.shares_client.update_share_type_extra_specs,
st["share_type"]["id"], {"": "new_value"})
@test.attr(type=["gate", "smoke", ])
def test_try_delete_spec_driver_handles_share_servers(self):
st = self._create_share_type()
# Try delete extra spec 'driver_handles_share_servers'
self.assertRaises(lib_exc.Forbidden,
self.shares_client.delete_share_type_extra_spec,
st["share_type"]["id"],
"driver_handles_share_servers")
@test.attr(type=["gate", "smoke", ])
def test_try_delete_spec_snapshot_support(self):
st = self._create_share_type()
# Try delete extra spec 'snapshot_support'
self.assertRaises(lib_exc.Forbidden,
self.shares_client.delete_share_type_extra_spec,
st["share_type"]["id"],
"snapshot_support")

View File

@ -0,0 +1,70 @@
# Copyright 2014 OpenStack Foundation
# 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 test # noqa
from tempest_lib.common.utils import data_utils # noqa
from tempest_lib import exceptions as lib_exc # noqa
from manila_tempest_tests import clients_share as clients
from manila_tempest_tests.tests.api import base
class ShareTypesAdminNegativeTest(base.BaseSharesAdminTest):
def _create_share_type(self):
name = data_utils.rand_name("unique_st_name")
extra_specs = self.add_required_extra_specs_to_dict({"key": "value"})
return self.create_share_type(name, extra_specs=extra_specs)
@classmethod
def resource_setup(cls):
super(ShareTypesAdminNegativeTest, cls).resource_setup()
cls.member_shares_client = clients.Manager().shares_client
@test.attr(type=["gate", "smoke", ])
def test_create_share_with_nonexistent_share_type(self):
self.assertRaises(lib_exc.NotFound,
self.create_share,
share_type_id=data_utils.rand_name("fake"))
@test.attr(type=["gate", "smoke", ])
def test_create_share_type_with_empty_name(self):
self.assertRaises(lib_exc.BadRequest, self.create_share_type, '')
@test.attr(type=["gate", "smoke", ])
def test_create_share_type_with_too_big_name(self):
self.assertRaises(lib_exc.BadRequest,
self.create_share_type,
"x" * 256)
@test.attr(type=["gate", "smoke", ])
def test_get_share_type_by_nonexistent_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share_type,
data_utils.rand_name("fake"))
@test.attr(type=["gate", "smoke", ])
def test_try_delete_share_type_by_nonexistent_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_share_type,
data_utils.rand_name("fake"))
@test.attr(type=["gate", "smoke", ])
def test_try_create_duplicate_of_share_type(self):
st = self._create_share_type()
self.assertRaises(lib_exc.Conflict,
self.create_share_type,
st["share_type"]["name"],
extra_specs=self.add_required_extra_specs_to_dict())

View File

@ -0,0 +1,373 @@
# Copyright 2014 Mirantis Inc. All Rights Reserved.
# Copyright (c) 2015 Yogesh Kshirsagar. 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 # noqa
from tempest import test # noqa
from tempest_lib.common.utils import data_utils # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class SharesActionsAdminTest(base.BaseSharesAdminTest):
"""Covers share functionality, that doesn't related to share type."""
@classmethod
def resource_setup(cls):
super(SharesActionsAdminTest, cls).resource_setup()
cls.shares = []
# create share type for share filtering purposes
cls.st_name = data_utils.rand_name("tempest-st-name")
cls.extra_specs = cls.add_required_extra_specs_to_dict(
{'storage_protocol': CONF.share.storage_protocol})
cls.st = cls.create_share_type(
name=cls.st_name,
cleanup_in_class=True,
extra_specs=cls.extra_specs,
)
# create share
cls.share_name = data_utils.rand_name("tempest-share-name")
cls.share_desc = data_utils.rand_name("tempest-share-description")
cls.metadata = {
'foo_key_share_1': 'foo_value_share_1',
'bar_key_share_1': 'foo_value_share_1',
}
cls.share_size = 1
cls.shares.append(cls.create_share(
name=cls.share_name,
description=cls.share_desc,
size=cls.share_size,
metadata=cls.metadata,
share_type_id=cls.st['share_type']['id'],
))
if CONF.share.run_snapshot_tests:
# create snapshot
cls.snap_name = data_utils.rand_name("tempest-snapshot-name")
cls.snap_desc = data_utils.rand_name(
"tempest-snapshot-description")
cls.snap = cls.create_snapshot_wait_for_active(
cls.shares[0]["id"], cls.snap_name, cls.snap_desc)
# create second share from snapshot for purposes of sorting and
# snapshot filtering
cls.share_name2 = data_utils.rand_name("tempest-share-name")
cls.share_desc2 = data_utils.rand_name("tempest-share-description")
cls.metadata2 = {
'foo_key_share_2': 'foo_value_share_2',
'bar_key_share_2': 'foo_value_share_2',
}
cls.shares.append(cls.create_share(
name=cls.share_name2,
description=cls.share_desc2,
size=cls.share_size,
metadata=cls.metadata2,
snapshot_id=cls.snap['id'],
))
@test.attr(type=["gate", ])
def test_get_share(self):
# get share
share = self.shares_client.get_share(self.shares[0]['id'])
# verify keys
expected_keys = ["status", "description", "links", "availability_zone",
"created_at", "export_location", "share_proto",
"name", "snapshot_id", "id", "size"]
actual_keys = share.keys()
[self.assertIn(key, actual_keys) for key in expected_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)
@test.attr(type=["gate", ])
def test_list_shares(self):
# list shares
shares = self.shares_client.list_shares()
# verify keys
keys = ["name", "id", "links"]
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
# our share id in list and have no duplicates
for share in self.shares:
gen = [sid["id"] for sid in shares if sid["id"] in share["id"]]
msg = "expected id lists %s times in share list" % (len(gen))
self.assertEqual(1, len(gen), msg)
@test.attr(type=["gate", ])
def test_list_shares_with_detail(self):
# list shares
shares = self.shares_client.list_shares_with_detail()
# verify keys
keys = [
"status", "description", "links", "availability_zone",
"created_at", "export_location", "share_proto", "host",
"name", "snapshot_id", "id", "size", "project_id",
]
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
# our shares in list and have no duplicates
for share in self.shares:
gen = [sid["id"] for sid in shares if sid["id"] in share["id"]]
msg = "expected id lists %s times in share list" % (len(gen))
self.assertEqual(1, len(gen), msg)
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_metadata(self):
filters = {'metadata': self.metadata}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
for share in shares:
self.assertDictContainsSubset(
filters['metadata'], share['metadata'])
if CONF.share.run_snapshot_tests:
self.assertFalse(self.shares[1]['id'] in [s['id'] for s in shares])
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_extra_specs(self):
filters = {
"extra_specs": {'storage_protocol': CONF.share.storage_protocol}
}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
shares_ids = [s["id"] for s in shares]
for share in self.shares:
self.assertTrue(share["id"] in shares_ids)
for share in shares:
st_list = self.shares_client.list_share_types()
# find its name or id, get id
sts = st_list["share_types"]
st_id = None
for st in sts:
if share["share_type"] in [st["id"], st["name"]]:
st_id = st["id"]
break
if st_id is None:
raise ValueError(
"Share '%(s_id)s' listed with extra_specs filter has "
"nonexistent share type '%(st)s'." % {
"s_id": share["id"], "st": share["share_type"]}
)
extra_specs = self.shares_client.get_share_type_extra_specs(st_id)
self.assertDictContainsSubset(filters["extra_specs"], extra_specs)
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_share_type_id(self):
filters = {'share_type_id': self.st['share_type']['id']}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
for share in shares:
st_list = self.shares_client.list_share_types()
# find its name or id, get id
sts = st_list["share_types"]
st_id = None
for st in sts:
if share["share_type"] in [st["id"], st["name"]]:
st_id = st["id"]
break
if st_id is None:
raise ValueError(
"Share '%(s_id)s' listed with share_type_id filter has "
"nonexistent share type '%(st)s'." % {
"s_id": share["id"], "st": share["share_type"]}
)
self.assertEqual(
filters['share_type_id'], st_id)
share_ids = [share['id'] for share in shares]
for share in self.shares:
self.assertTrue(share['id'] in share_ids)
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_host(self):
base_share = self.shares_client.get_share(self.shares[0]['id'])
filters = {'host': base_share['host']}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
for share in shares:
self.assertEqual(filters['host'], share['host'])
@test.attr(type=["gate", ])
@testtools.skipIf(
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
def test_list_shares_with_detail_filter_by_share_network_id(self):
base_share = self.shares_client.get_share(self.shares[0]['id'])
filters = {'share_network_id': base_share['share_network_id']}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
for share in shares:
self.assertEqual(
filters['share_network_id'], share['share_network_id'])
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_list_shares_with_detail_filter_by_snapshot_id(self):
filters = {'snapshot_id': self.snap['id']}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
for share in shares:
self.assertEqual(filters['snapshot_id'], share['snapshot_id'])
self.assertFalse(self.shares[0]['id'] in [s['id'] for s in shares])
@test.attr(type=["gate", ])
def test_list_shares_with_detail_with_asc_sorting(self):
filters = {'sort_key': 'created_at', 'sort_dir': 'asc'}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
sorted_list = [share['created_at'] for share in shares]
self.assertEqual(sorted_list, sorted(sorted_list))
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_existed_name(self):
# list shares by name, at least one share is expected
params = {"name": self.share_name}
shares = self.shares_client.list_shares_with_detail(params)
self.assertEqual(shares[0]["name"], self.share_name)
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_fake_name(self):
# list shares by fake name, no shares are expected
params = {"name": data_utils.rand_name("fake-nonexistent-name")}
shares = self.shares_client.list_shares_with_detail(params)
self.assertEqual(0, len(shares))
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_active_status(self):
# list shares by active status, at least one share is expected
params = {"status": "available"}
shares = self.shares_client.list_shares_with_detail(params)
self.assertTrue(len(shares) > 0)
for share in shares:
self.assertEqual(share["status"], params["status"])
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_fake_status(self):
# list shares by fake status, no shares are expected
params = {"status": 'fake'}
shares = self.shares_client.list_shares_with_detail(params)
self.assertEqual(0, len(shares))
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_get_snapshot(self):
# get snapshot
get = self.shares_client.get_snapshot(self.snap["id"])
# verify keys
expected_keys = ["status", "links", "share_id", "name",
"share_proto", "created_at",
"description", "id", "share_size"]
actual_keys = get.keys()
[self.assertIn(key, actual_keys) for key in expected_keys]
# verify data
msg = "Expected name: '%s', actual name: '%s'" % (self.snap_name,
get["name"])
self.assertEqual(self.snap_name, get["name"], msg)
msg = "Expected description: '%s', "\
"actual description: '%s'" % (self.snap_desc, get["description"])
self.assertEqual(self.snap_desc, get["description"], msg)
msg = "Expected share_id: '%s', "\
"actual share_id: '%s'" % (self.shares[0]["id"], get["share_id"])
self.assertEqual(self.shares[0]["id"], get["share_id"], msg)
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_list_snapshots(self):
# list share snapshots
snaps = self.shares_client.list_snapshots()
# verify keys
keys = ["id", "name", "links"]
[self.assertIn(key, sn.keys()) for sn in snaps for key in keys]
# our share id in list and have no duplicates
gen = [sid["id"] for sid in snaps if sid["id"] in self.snap["id"]]
msg = "expected id lists %s times in share list" % (len(gen))
self.assertEqual(1, len(gen), msg)
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_list_snapshots_with_detail(self):
# list share snapshots
snaps = self.shares_client.list_snapshots_with_detail()
# verify keys
keys = ["status", "links", "share_id", "name",
"share_proto", "created_at",
"description", "id", "share_size"]
[self.assertIn(key, sn.keys()) for sn in snaps for key in keys]
# our share id in list and have no duplicates
gen = [sid["id"] for sid in snaps if sid["id"] in self.snap["id"]]
msg = "expected id lists %s times in share list" % (len(gen))
self.assertEqual(1, len(gen), msg)

View File

@ -0,0 +1,618 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
import inspect
import traceback
from oslo_concurrency import lockutils
from oslo_log import log
import six
from tempest.common import isolated_creds # noqa
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions
from manila_tempest_tests import clients_share as clients
from manila_tempest_tests import share_exceptions
CONF = config.CONF
LOG = log.getLogger(__name__)
class handle_cleanup_exceptions(object):
"""Handle exceptions raised with cleanup operations.
Always suppress errors when exceptions.NotFound or exceptions.Forbidden
are raised.
Suppress all other exceptions only in case config opt
'suppress_errors_in_cleanup' in config group 'share' is True.
"""
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
if not (isinstance(exc_value,
(exceptions.NotFound, exceptions.Forbidden)) or
CONF.share.suppress_errors_in_cleanup):
return False # Do not suppress error if any
if exc_traceback:
LOG.error("Suppressed cleanup error in Manila: "
"\n%s" % traceback.format_exc())
return True # Suppress error if any
def network_synchronized(f):
def wrapped_func(self, *args, **kwargs):
with_isolated_creds = True if len(args) > 2 else False
no_lock_required = kwargs.get(
"isolated_creds_client", with_isolated_creds)
if no_lock_required:
# Usage of not reusable network. No need in lock.
return f(self, *args, **kwargs)
# Use lock assuming reusage of common network.
@lockutils.synchronized("manila_network_lock", external=True)
def source_func(self, *args, **kwargs):
return f(self, *args, **kwargs)
return source_func(self, *args, **kwargs)
return wrapped_func
class BaseSharesTest(test.BaseTestCase):
"""Base test case class for all Manila API tests."""
force_tenant_isolation = False
protocols = ["nfs", "cifs", "glusterfs", "hdfs"]
# Will be cleaned up in resource_cleanup
class_resources = []
# Will be cleaned up in tearDown method
method_resources = []
# Will be cleaned up in resource_cleanup
class_isolated_creds = []
# Will be cleaned up in tearDown method
method_isolated_creds = []
@classmethod
def get_client_with_isolated_creds(cls,
name=None,
type_of_creds="admin",
cleanup_in_class=False):
"""Creates isolated creds.
:param name: name, will be used for naming ic and related stuff
:param type_of_creds: admin, alt or primary
:param cleanup_in_class: defines place where to delete
:returns: SharesClient -- shares client with isolated creds.
:returns: To client added dict attr 'creds' with
:returns: key elements 'tenant' and 'user'.
"""
if name is None:
# Get name of test method
name = inspect.stack()[1][3]
if len(name) > 32:
name = name[0:32]
# Choose type of isolated creds
ic = isolated_creds.IsolatedCreds(name=name)
if "admin" in type_of_creds:
creds = ic.get_admin_creds()
elif "alt" in type_of_creds:
creds = ic.get_alt_creds()
else:
creds = ic.self.get_credentials(type_of_creds)
ic.type_of_creds = type_of_creds
# create client with isolated creds
os = clients.Manager(credentials=creds)
client = os.shares_client
# Set place where will be deleted isolated creds
ic_res = {
"method": ic.clear_isolated_creds,
"deleted": False,
}
if cleanup_in_class:
cls.class_isolated_creds.insert(0, ic_res)
else:
cls.method_isolated_creds.insert(0, ic_res)
# Provide share network
if CONF.share.multitenancy_enabled:
if not CONF.service_available.neutron:
raise cls.skipException("Neutron support is required")
nc = os.network_client
share_network_id = cls.provide_share_network(client, nc, ic)
client.share_network_id = share_network_id
resource = {
"type": "share_network",
"id": client.share_network_id,
"client": client,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
return client
@classmethod
def verify_nonempty(cls, *args):
if not all(args):
msg = "Missing API credentials in configuration."
raise cls.skipException(msg)
@classmethod
def resource_setup(cls):
if not (any(p in CONF.share.enable_protocols
for p in cls.protocols) and
CONF.service_available.manila):
skip_msg = "Manila is disabled"
raise cls.skipException(skip_msg)
super(BaseSharesTest, cls).resource_setup()
if not hasattr(cls, "os"):
cls.username = CONF.identity.username
cls.password = CONF.identity.password
cls.tenant_name = CONF.identity.tenant_name
cls.verify_nonempty(cls.username, cls.password, cls.tenant_name)
cls.os = clients.Manager()
if CONF.share.multitenancy_enabled:
if not CONF.service_available.neutron:
raise cls.skipException("Neutron support is required")
sc = cls.os.shares_client
nc = cls.os.network_client
share_network_id = cls.provide_share_network(sc, nc)
cls.os.shares_client.share_network_id = share_network_id
cls.shares_client = cls.os.shares_client
def setUp(self):
super(BaseSharesTest, self).setUp()
self.addCleanup(self.clear_resources)
self.addCleanup(self.clear_isolated_creds)
@classmethod
def resource_cleanup(cls):
super(BaseSharesTest, cls).resource_cleanup()
cls.clear_resources(cls.class_resources)
cls.clear_isolated_creds(cls.class_isolated_creds)
@classmethod
@network_synchronized
def provide_share_network(cls, shares_client, network_client,
isolated_creds_client=None):
"""Used for finding/creating share network for multitenant driver.
This method creates/gets entity share-network for one tenant. This
share-network will be used for creation of service vm.
:param shares_client: shares client, which requires share-network
:param network_client: network client from same tenant as shares
:param isolated_creds_client: IsolatedCreds instance
If provided, then its networking will be used if needed.
If not provided, then common network will be used if needed.
:returns: str -- share network id for shares_client tenant
:returns: None -- if single-tenant driver used
"""
sc = shares_client
if not CONF.share.multitenancy_enabled:
# Assumed usage of a single-tenant driver
share_network_id = None
elif sc.share_network_id:
# Share-network already exists, use it
share_network_id = sc.share_network_id
else:
net_id = subnet_id = share_network_id = None
if not isolated_creds_client:
# Search for networks, created in previous runs
search_word = "reusable"
sn_name = "autogenerated_by_tempest_%s" % search_word
service_net_name = "share-service"
networks = network_client.list_networks()
if "networks" in networks.keys():
networks = networks["networks"]
for network in networks:
if (service_net_name in network["name"] and
sc.tenant_id == network['tenant_id']):
net_id = network["id"]
if len(network["subnets"]) > 0:
subnet_id = network["subnets"][0]
break
# Create suitable network
if (net_id is None or subnet_id is None):
ic = isolated_creds.IsolatedCreds(name=service_net_name)
net_data = ic._create_network_resources(sc.tenant_id)
network, subnet, router = net_data
net_id = network["id"]
subnet_id = subnet["id"]
# Try get suitable share-network
share_networks = sc.list_share_networks_with_detail()
for sn in share_networks:
if (net_id == sn["neutron_net_id"] and
subnet_id == sn["neutron_subnet_id"] and
sn["name"] and search_word in sn["name"]):
share_network_id = sn["id"]
break
else:
sn_name = "autogenerated_by_tempest_for_isolated_creds"
# Use precreated network and subnet from isolated creds
net_id = isolated_creds_client.get_credentials(
isolated_creds_client.type_of_creds).network['id']
subnet_id = isolated_creds_client.get_credentials(
isolated_creds_client.type_of_creds).subnet['id']
# Create suitable share-network
if share_network_id is None:
sn_desc = "This share-network was created by tempest"
sn = sc.create_share_network(name=sn_name,
description=sn_desc,
neutron_net_id=net_id,
neutron_subnet_id=subnet_id)
share_network_id = sn["id"]
return share_network_id
@classmethod
def _create_share(cls, share_protocol=None, size=1, name=None,
snapshot_id=None, description=None, metadata=None,
share_network_id=None, share_type_id=None,
client=None, cleanup_in_class=True, is_public=False):
client = client or cls.shares_client
description = description or "Tempest's share"
share_network_id = share_network_id or client.share_network_id or None
metadata = metadata or {}
kwargs = {
'share_protocol': share_protocol,
'size': size,
'name': name,
'snapshot_id': snapshot_id,
'description': description,
'metadata': metadata,
'share_network_id': share_network_id,
'share_type_id': share_type_id,
'is_public': is_public,
}
share = client.create_share(**kwargs)
resource = {"type": "share", "id": share["id"], "client": client}
cleanup_list = (cls.class_resources if cleanup_in_class else
cls.method_resources)
cleanup_list.insert(0, resource)
return share
@classmethod
def create_share(cls, *args, **kwargs):
"""Create one share and wait for available state. Retry if allowed."""
result = cls.create_shares([{"args": args, "kwargs": kwargs}])
return result[0]
@classmethod
def create_shares(cls, share_data_list):
"""Creates several shares in parallel with retries.
Use this method when you want to create more than one share at same
time. Especially if config option 'share.share_creation_retry_number'
has value more than zero (0).
All shares will be expected to have 'available' status with or without
recreation else error will be raised.
:param share_data_list: list -- list of dictionaries with 'args' and
'kwargs' for '_create_share' method of this base class.
example of data:
share_data_list=[{'args': ['quuz'], 'kwargs': {'foo': 'bar'}}}]
:returns: list -- list of shares created using provided data.
"""
data = [copy.deepcopy(d) for d in share_data_list]
for d in data:
if not isinstance(d, dict):
raise exceptions.TempestException(
"Expected 'dict', got '%s'" % type(d))
if "args" not in d:
d["args"] = []
if "kwargs" not in d:
d["kwargs"] = {}
if len(d) > 2:
raise exceptions.TempestException(
"Expected only 'args' and 'kwargs' keys. "
"Provided %s" % list(d))
d["kwargs"]["client"] = d["kwargs"].get(
"client", cls.shares_client)
d["share"] = cls._create_share(*d["args"], **d["kwargs"])
d["cnt"] = 0
d["available"] = False
while not all(d["available"] for d in data):
for d in data:
if d["available"]:
continue
try:
d["kwargs"]["client"].wait_for_share_status(
d["share"]["id"], "available")
d["available"] = True
except (share_exceptions.ShareBuildErrorException,
exceptions.TimeoutException) as e:
if CONF.share.share_creation_retry_number > d["cnt"]:
d["cnt"] += 1
msg = ("Share '%s' failed to be built. "
"Trying create another." % d["share"]["id"])
LOG.error(msg)
LOG.error(e)
d["share"] = cls._create_share(
*d["args"], **d["kwargs"])
else:
raise e
return [d["share"] for d in data]
@classmethod
def create_snapshot_wait_for_active(cls, share_id, name=None,
description=None, force=False,
client=None, cleanup_in_class=True):
if client is None:
client = cls.shares_client
if description is None:
description = "Tempest's snapshot"
snapshot = client.create_snapshot(share_id, name, description, force)
resource = {
"type": "snapshot",
"id": snapshot["id"],
"client": client,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
client.wait_for_snapshot_status(snapshot["id"], "available")
return snapshot
@classmethod
def create_share_network(cls, client=None,
cleanup_in_class=False, **kwargs):
if client is None:
client = cls.shares_client
share_network = client.create_share_network(**kwargs)
resource = {
"type": "share_network",
"id": share_network["id"],
"client": client,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
return share_network
@classmethod
def create_security_service(cls, ss_type="ldap", client=None,
cleanup_in_class=False, **kwargs):
if client is None:
client = cls.shares_client
security_service = client.create_security_service(ss_type, **kwargs)
resource = {
"type": "security_service",
"id": security_service["id"],
"client": client,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
return security_service
@classmethod
def create_share_type(cls, name, is_public=True, client=None,
cleanup_in_class=True, **kwargs):
if client is None:
client = cls.shares_client
share_type = client.create_share_type(name, is_public, **kwargs)
resource = {
"type": "share_type",
"id": share_type["share_type"]["id"],
"client": client,
}
if cleanup_in_class:
cls.class_resources.insert(0, resource)
else:
cls.method_resources.insert(0, resource)
return share_type
@staticmethod
def add_required_extra_specs_to_dict(extra_specs=None):
value = six.text_type(CONF.share.multitenancy_enabled)
required = {
"driver_handles_share_servers": value,
"snapshot_support": 'True',
}
if extra_specs:
required.update(extra_specs)
return required
@classmethod
def clear_isolated_creds(cls, creds=None):
if creds is None:
creds = cls.method_isolated_creds
for ic in creds:
if "deleted" not in ic.keys():
ic["deleted"] = False
if not ic["deleted"]:
with handle_cleanup_exceptions():
ic["method"]()
ic["deleted"] = True
@classmethod
def clear_resources(cls, resources=None):
"""Deletes resources, that were created in test suites.
This method tries to remove resources from resource list,
if it is not found, assumed it was deleted in test itself.
It is expected, that all resources were added as LIFO
due to restriction of deletion resources, that is in the chain.
:param resources: dict with keys 'type','id','client' and 'deleted'
"""
if resources is None:
resources = cls.method_resources
for res in resources:
if "deleted" not in res.keys():
res["deleted"] = False
if "client" not in res.keys():
res["client"] = cls.shares_client
if not(res["deleted"]):
res_id = res['id']
client = res["client"]
with handle_cleanup_exceptions():
if res["type"] is "share":
client.delete_share(res_id)
client.wait_for_resource_deletion(share_id=res_id)
elif res["type"] is "snapshot":
client.delete_snapshot(res_id)
client.wait_for_resource_deletion(snapshot_id=res_id)
elif res["type"] is "share_network":
client.delete_share_network(res_id)
client.wait_for_resource_deletion(sn_id=res_id)
elif res["type"] is "security_service":
client.delete_security_service(res_id)
client.wait_for_resource_deletion(ss_id=res_id)
elif res["type"] is "share_type":
client.delete_share_type(res_id)
client.wait_for_resource_deletion(st_id=res_id)
else:
LOG.warn("Provided unsupported resource type for "
"cleanup '%s'. Skipping." % res["type"])
res["deleted"] = True
@classmethod
def generate_share_network_data(self):
data = {
"name": data_utils.rand_name("sn-name"),
"description": data_utils.rand_name("sn-desc"),
"neutron_net_id": data_utils.rand_name("net-id"),
"neutron_subnet_id": data_utils.rand_name("subnet-id"),
}
return data
@classmethod
def generate_security_service_data(self):
data = {
"name": data_utils.rand_name("ss-name"),
"description": data_utils.rand_name("ss-desc"),
"dns_ip": data_utils.rand_name("ss-dns_ip"),
"server": data_utils.rand_name("ss-server"),
"domain": data_utils.rand_name("ss-domain"),
"user": data_utils.rand_name("ss-user"),
"password": data_utils.rand_name("ss-password"),
}
return data
# Useful assertions
def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001):
"""Assert two dicts are equivalent.
This is a 'deep' match in the sense that it handles nested
dictionaries appropriately.
NOTE:
If you don't care (or don't know) a given value, you can specify
the string DONTCARE as the value. This will cause that dict-item
to be skipped.
"""
def raise_assertion(msg):
d1str = str(d1)
d2str = str(d2)
base_msg = ('Dictionaries do not match. %(msg)s d1: %(d1str)s '
'd2: %(d2str)s' %
{"msg": msg, "d1str": d1str, "d2str": d2str})
raise AssertionError(base_msg)
d1keys = set(d1.keys())
d2keys = set(d2.keys())
if d1keys != d2keys:
d1only = d1keys - d2keys
d2only = d2keys - d1keys
raise_assertion('Keys in d1 and not d2: %(d1only)s. '
'Keys in d2 and not d1: %(d2only)s' %
{"d1only": d1only, "d2only": d2only})
for key in d1keys:
d1value = d1[key]
d2value = d2[key]
try:
error = abs(float(d1value) - float(d2value))
within_tolerance = error <= tolerance
except (ValueError, TypeError):
# If both values aren't convertable to float, just ignore
# ValueError if arg is a str, TypeError if it's something else
# (like None)
within_tolerance = False
if hasattr(d1value, 'keys') and hasattr(d2value, 'keys'):
self.assertDictMatch(d1value, d2value)
elif 'DONTCARE' in (d1value, d2value):
continue
elif approx_equal and within_tolerance:
continue
elif d1value != d2value:
raise_assertion("d1['%(key)s']=%(d1value)s != "
"d2['%(key)s']=%(d2value)s" %
{
"key": key,
"d1value": d1value,
"d2value": d2value
})
class BaseSharesAltTest(BaseSharesTest):
"""Base test case class for all Shares Alt API tests."""
@classmethod
def resource_setup(cls):
cls.username = CONF.identity.alt_username
cls.password = CONF.identity.alt_password
cls.tenant_name = CONF.identity.alt_tenant_name
cls.verify_nonempty(cls.username, cls.password, cls.tenant_name)
cls.os = clients.AltManager()
alt_share_network_id = CONF.share.alt_share_network_id
cls.os.shares_client.share_network_id = alt_share_network_id
super(BaseSharesAltTest, cls).resource_setup()
class BaseSharesAdminTest(BaseSharesTest):
"""Base test case class for all Shares Admin API tests."""
@classmethod
def resource_setup(cls):
cls.username = CONF.identity.admin_username
cls.password = CONF.identity.admin_password
cls.tenant_name = CONF.identity.admin_tenant_name
cls.verify_nonempty(cls.username, cls.password, cls.tenant_name)
cls.os = clients.AdminManager()
admin_share_network_id = CONF.share.admin_share_network_id
cls.os.shares_client.share_network_id = admin_share_network_id
super(BaseSharesAdminTest, cls).resource_setup()

View File

@ -0,0 +1,31 @@
# Copyright 2014 mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from manila_tempest_tests.tests.api import base
class ExtensionsTest(base.BaseSharesTest):
@test.attr(type=["smoke", "gate"])
def test_extensions(self):
# get extensions
extensions = self.shares_client.list_extensions()
# verify response
keys = ["alias", "updated", "name", "description"]
[self.assertIn(key, ext.keys()) for ext in extensions for key in keys]

View File

@ -0,0 +1,60 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from manila_tempest_tests.tests.api import base
class ShareLimitsTest(base.BaseSharesTest):
@test.attr(type=["gate", "smoke", ])
def test_limits_keys(self):
# list limits
limits = self.shares_client.get_limits()
# verify response
keys = ["rate", "absolute"]
[self.assertIn(key, limits.keys()) for key in keys]
abs_keys = [
"maxTotalShareGigabytes",
"maxTotalShares",
"maxTotalShareSnapshots",
"maxTotalShareNetworks",
"totalSharesUsed",
"totalShareSnapshotsUsed",
"totalShareNetworksUsed",
"totalShareGigabytesUsed",
]
[self.assertIn(key, limits["absolute"].keys()) for key in abs_keys]
@test.attr(type=["gate", "smoke", ])
def test_limits_values(self):
# list limits
limits = self.shares_client.get_limits()
# verify integer values for absolute limits
abs_l = limits["absolute"]
self.assertGreater(int(abs_l["maxTotalShareGigabytes"]), -2)
self.assertGreater(int(abs_l["maxTotalShares"]), -2)
self.assertGreater(int(abs_l["maxTotalShareSnapshots"]), -2)
self.assertGreater(int(abs_l["maxTotalShareNetworks"]), -2)
self.assertGreater(int(abs_l["totalSharesUsed"]), -2)
self.assertGreater(int(abs_l["totalShareSnapshotsUsed"]), -2)
self.assertGreater(int(abs_l["totalShareNetworksUsed"]), -2)
self.assertGreater(int(abs_l["totalShareGigabytesUsed"]), -2)

View File

@ -0,0 +1,163 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from manila_tempest_tests.tests.api import base
class SharesMetadataTest(base.BaseSharesTest):
@classmethod
def resource_setup(cls):
super(SharesMetadataTest, cls).resource_setup()
cls.share = cls.create_share()
@test.attr(type=["gate", ])
def test_set_metadata_in_share_creation(self):
md = {u"key1": u"value1", u"key2": u"value2", }
# create share with metadata
share = self.create_share(metadata=md, cleanup_in_class=False)
# get metadata of share
metadata = self.shares_client.get_metadata(share["id"])
# verify metadata
self.assertEqual(md, metadata)
@test.attr(type=["gate", ])
def test_set_get_delete_metadata(self):
md = {u"key3": u"value3", u"key4": u"value4", }
# create share
share = self.create_share(cleanup_in_class=False)
# set metadata
self.shares_client.set_metadata(share["id"], md)
# read metadata
get_md = self.shares_client.get_metadata(share["id"])
# verify metadata
self.assertEqual(md, get_md)
# delete metadata
for key in md.keys():
self.shares_client.delete_metadata(share["id"], key)
# verify deletion of metadata
get_metadata = self.shares_client.get_metadata(share["id"])
self.assertEqual({}, get_metadata)
@test.attr(type=["gate", ])
def test_set_and_update_metadata_by_key(self):
md1 = {u"key5": u"value5", u"key6": u"value6", }
md2 = {u"key7": u"value7", u"key8": u"value8", }
# create share
share = self.create_share(cleanup_in_class=False)
# set metadata
self.shares_client.set_metadata(share["id"], md1)
# update metadata
self.shares_client.update_all_metadata(share["id"], md2)
# get metadata
get_md = self.shares_client.get_metadata(share["id"])
# verify metadata
self.assertEqual(md2, get_md)
@test.attr(type=["gate", ])
def test_set_metadata_min_size_key(self):
data = {"k": "value"}
self.shares_client.set_metadata(self.share["id"], data)
body_get = self.shares_client.get_metadata(self.share["id"])
self.assertEqual(data['k'], body_get.get('k'))
@test.attr(type=["gate", ])
def test_set_metadata_max_size_key(self):
max_key = "k" * 255
data = {max_key: "value"}
self.shares_client.set_metadata(self.share["id"], data)
body_get = self.shares_client.get_metadata(self.share["id"])
self.assertIn(max_key, body_get)
self.assertEqual(data[max_key], body_get.get(max_key))
@test.attr(type=["gate", ])
def test_set_metadata_min_size_value(self):
data = {"key": "v"}
self.shares_client.set_metadata(self.share["id"], data)
body_get = self.shares_client.get_metadata(self.share["id"])
self.assertEqual(data['key'], body_get['key'])
@test.attr(type=["gate", ])
def test_set_metadata_max_size_value(self):
max_value = "v" * 1023
data = {"key": max_value}
self.shares_client.set_metadata(self.share["id"], data)
body_get = self.shares_client.get_metadata(self.share["id"])
self.assertEqual(data['key'], body_get['key'])
@test.attr(type=["gate", ])
def test_upd_metadata_min_size_key(self):
data = {"k": "value"}
self.shares_client.update_all_metadata(self.share["id"], data)
body_get = self.shares_client.get_metadata(self.share["id"])
self.assertEqual(data, body_get)
@test.attr(type=["gate", ])
def test_upd_metadata_max_size_key(self):
max_key = "k" * 255
data = {max_key: "value"}
self.shares_client.update_all_metadata(self.share["id"], data)
body_get = self.shares_client.get_metadata(self.share["id"])
self.assertEqual(data, body_get)
@test.attr(type=["gate", ])
def test_upd_metadata_min_size_value(self):
data = {"key": "v"}
self.shares_client.update_all_metadata(self.share["id"], data)
body_get = self.shares_client.get_metadata(self.share["id"])
self.assertEqual(data, body_get)
@test.attr(type=["gate", ])
def test_upd_metadata_max_size_value(self):
max_value = "v" * 1023
data = {"key": max_value}
self.shares_client.update_all_metadata(self.share["id"], data)
body_get = self.shares_client.get_metadata(self.share["id"])
self.assertEqual(data, body_get)

View File

@ -0,0 +1,91 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
from manila_tempest_tests.tests.api import base
class SharesMetadataNegativeTest(base.BaseSharesTest):
@classmethod
def resource_setup(cls):
super(SharesMetadataNegativeTest, cls).resource_setup()
cls.share = cls.create_share()
@test.attr(type=["gate", "negative", ])
def test_try_set_metadata_to_unexisting_share(self):
md = {u"key1": u"value1", u"key2": u"value2", }
self.assertRaises(lib_exc.NotFound,
self.shares_client.set_metadata,
"wrong_share_id", md)
@test.attr(type=["gate", "negative", ])
def test_try_update_all_metadata_for_unexisting_share(self):
md = {u"key1": u"value1", u"key2": u"value2", }
self.assertRaises(lib_exc.NotFound,
self.shares_client.update_all_metadata,
"wrong_share_id", md)
@test.attr(type=["gate", "negative", ])
def test_try_set_metadata_with_empty_key(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.set_metadata,
self.share["id"], {"": "value"})
@test.attr(type=["gate", "negative", ])
def test_try_upd_metadata_with_empty_key(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.update_all_metadata,
self.share["id"], {"": "value"})
@test.attr(type=["gate", "negative", ])
def test_try_set_metadata_with_too_big_key(self):
too_big_key = "x" * 256
md = {too_big_key: "value"}
self.assertRaises(lib_exc.BadRequest,
self.shares_client.set_metadata,
self.share["id"], md)
@test.attr(type=["gate", "negative", ])
def test_try_upd_metadata_with_too_big_key(self):
too_big_key = "x" * 256
md = {too_big_key: "value"}
self.assertRaises(lib_exc.BadRequest,
self.shares_client.update_all_metadata,
self.share["id"], md)
@test.attr(type=["gate", "negative", ])
def test_try_set_metadata_with_too_big_value(self):
too_big_value = "x" * 1024
md = {"key": too_big_value}
self.assertRaises(lib_exc.BadRequest,
self.shares_client.set_metadata,
self.share["id"], md)
@test.attr(type=["gate", "negative", ])
def test_try_upd_metadata_with_too_big_value(self):
too_big_value = "x" * 1024
md = {"key": too_big_value}
self.assertRaises(lib_exc.BadRequest,
self.shares_client.update_all_metadata,
self.share["id"], md)
@test.attr(type=["gate", "negative", ])
def test_try_delete_unexisting_metadata(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_metadata,
self.share["id"], "wrong_key")

View File

@ -0,0 +1,55 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from manila_tempest_tests.tests.api import base
class SharesQuotasTest(base.BaseSharesTest):
@classmethod
def resource_setup(cls):
super(SharesQuotasTest, cls).resource_setup()
cls.user_id = cls.shares_client.user_id
cls.tenant_id = cls.shares_client.tenant_id
@test.attr(type=["gate", "smoke", ])
def test_default_quotas(self):
quotas = self.shares_client.default_quotas(self.tenant_id)
self.assertGreater(int(quotas["gigabytes"]), -2)
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
self.assertGreater(int(quotas["shares"]), -2)
self.assertGreater(int(quotas["snapshots"]), -2)
self.assertGreater(int(quotas["share_networks"]), -2)
@test.attr(type=["gate", "smoke", ])
def test_show_quotas(self):
quotas = self.shares_client.show_quotas(self.tenant_id)
self.assertGreater(int(quotas["gigabytes"]), -2)
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
self.assertGreater(int(quotas["shares"]), -2)
self.assertGreater(int(quotas["snapshots"]), -2)
self.assertGreater(int(quotas["share_networks"]), -2)
@test.attr(type=["gate", "smoke", ])
def test_show_quotas_for_user(self):
quotas = self.shares_client.show_quotas(
self.tenant_id, self.user_id)
self.assertGreater(int(quotas["gigabytes"]), -2)
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
self.assertGreater(int(quotas["shares"]), -2)
self.assertGreater(int(quotas["snapshots"]), -2)
self.assertGreater(int(quotas["share_networks"]), -2)

View File

@ -0,0 +1,41 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
class SharesQuotasNegativeTest(base.BaseSharesTest):
@test.attr(type=["gate", "smoke", "negative"])
def test_get_quotas_with_empty_tenant_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.show_quotas, "")
@test.attr(type=["gate", "smoke", "negative", ])
def test_try_reset_quotas_with_user(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.reset_quotas,
self.shares_client.tenant_id)
@test.attr(type=["gate", "smoke", "negative", ])
def test_try_update_quotas_with_user(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.update_quotas,
self.shares_client.tenant_id,
shares=9)

View File

@ -0,0 +1,285 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
def _create_delete_ro_access_rule(self):
"""Common test case for usage in test suites with different decorators.
:param self: instance of test class
"""
rule = self.shares_client.create_access_rule(
self.share["id"], self.access_type, self.access_to, 'ro')
self.assertEqual('ro', rule['access_level'])
self.shares_client.wait_for_access_rule_status(
self.share["id"], rule["id"], "active")
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
self.shares_client.wait_for_resource_deletion(
rule_id=rule["id"], share_id=self.share['id'])
class ShareIpRulesForNFSTest(base.BaseSharesTest):
protocol = "nfs"
@classmethod
def resource_setup(cls):
super(ShareIpRulesForNFSTest, cls).resource_setup()
if (cls.protocol not in CONF.share.enable_protocols or
cls.protocol not in CONF.share.enable_ip_rules_for_protocols):
msg = "IP rule tests for %s protocol are disabled" % cls.protocol
raise cls.skipException(msg)
cls.share = cls.create_share(cls.protocol)
cls.access_type = "ip"
cls.access_to = "2.2.2.2"
@test.attr(type=["gate", ])
def test_create_delete_access_rules_with_one_ip(self):
# test data
access_to = "1.1.1.1"
# create rule
rule = self.shares_client.create_access_rule(
self.share["id"], self.access_type, access_to)
self.assertEqual('rw', rule['access_level'])
self.shares_client.wait_for_access_rule_status(
self.share["id"], rule["id"], "active")
# delete rule and wait for deletion
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
self.shares_client.wait_for_resource_deletion(
rule_id=rule["id"], share_id=self.share['id'])
@test.attr(type=["gate", ])
def test_create_delete_access_rule_with_cidr(self):
# test data
access_to = "1.2.3.4/32"
# create rule
rule = self.shares_client.create_access_rule(
self.share["id"], self.access_type, access_to)
self.assertEqual('rw', rule['access_level'])
self.shares_client.wait_for_access_rule_status(
self.share["id"], rule["id"], "active")
# delete rule and wait for deletion
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
self.shares_client.wait_for_resource_deletion(
rule_id=rule["id"], share_id=self.share['id'])
@test.attr(type=["gate", ])
@testtools.skipIf(
"nfs" not in CONF.share.enable_ro_access_level_for_protocols,
"RO access rule tests are disabled for NFS protocol.")
def test_create_delete_ro_access_rule(self):
_create_delete_ro_access_rule(self)
class ShareIpRulesForCIFSTest(ShareIpRulesForNFSTest):
protocol = "cifs"
@test.attr(type=["gate", ])
@testtools.skipIf(
"cifs" not in CONF.share.enable_ro_access_level_for_protocols,
"RO access rule tests are disabled for CIFS protocol.")
def test_create_delete_ro_access_rule(self):
_create_delete_ro_access_rule(self)
class ShareUserRulesForNFSTest(base.BaseSharesTest):
protocol = "nfs"
@classmethod
def resource_setup(cls):
super(ShareUserRulesForNFSTest, cls).resource_setup()
if (cls.protocol not in CONF.share.enable_protocols or
cls.protocol not in
CONF.share.enable_user_rules_for_protocols):
msg = "USER rule tests for %s protocol are disabled" % cls.protocol
raise cls.skipException(msg)
cls.share = cls.create_share(cls.protocol)
cls.access_type = "user"
cls.access_to = CONF.share.username_for_user_rules
@test.attr(type=["gate", ])
def test_create_delete_user_rule(self):
# create rule
rule = self.shares_client.create_access_rule(
self.share["id"], self.access_type, self.access_to)
self.assertEqual('rw', rule['access_level'])
self.shares_client.wait_for_access_rule_status(
self.share["id"], rule["id"], "active")
# delete rule and wait for deletion
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
self.shares_client.wait_for_resource_deletion(
rule_id=rule["id"], share_id=self.share['id'])
@test.attr(type=["gate", ])
@testtools.skipIf(
"nfs" not in CONF.share.enable_ro_access_level_for_protocols,
"RO access rule tests are disabled for NFS protocol.")
def test_create_delete_ro_access_rule(self):
_create_delete_ro_access_rule(self)
class ShareUserRulesForCIFSTest(ShareUserRulesForNFSTest):
protocol = "cifs"
@test.attr(type=["gate", ])
@testtools.skipIf(
"cifs" not in CONF.share.enable_ro_access_level_for_protocols,
"RO access rule tests are disabled for CIFS protocol.")
def test_create_delete_ro_access_rule(self):
_create_delete_ro_access_rule(self)
class ShareCertRulesForGLUSTERFSTest(base.BaseSharesTest):
protocol = "glusterfs"
@classmethod
def resource_setup(cls):
super(ShareCertRulesForGLUSTERFSTest, cls).resource_setup()
if (cls.protocol not in CONF.share.enable_protocols or
cls.protocol not in
CONF.share.enable_cert_rules_for_protocols):
msg = "Cert rule tests for %s protocol are disabled" % cls.protocol
raise cls.skipException(msg)
cls.share = cls.create_share(cls.protocol)
cls.access_type = "cert"
# Provide access to a client identified by a common name (CN) of the
# certificate that it possesses.
cls.access_to = "client1.com"
@test.attr(type=["gate", ])
def test_create_delete_cert_rule(self):
# create rule
rule = self.shares_client.create_access_rule(
self.share["id"], self.access_type, self.access_to)
self.assertEqual('rw', rule['access_level'])
self.shares_client.wait_for_access_rule_status(
self.share["id"], rule["id"], "active")
# delete rule
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
@test.attr(type=["gate", ])
@testtools.skipIf(
"glusterfs" not in CONF.share.enable_ro_access_level_for_protocols,
"RO access rule tests are disabled for GLUSTERFS protocol.")
def test_create_delete_cert_ro_access_rule(self):
rule = self.shares_client.create_access_rule(
self.share["id"], 'cert', 'client2.com', 'ro')
self.assertEqual('ro', rule['access_level'])
self.shares_client.wait_for_access_rule_status(
self.share["id"], rule["id"], "active")
self.shares_client.delete_access_rule(self.share["id"], rule["id"])
class ShareRulesTest(base.BaseSharesTest):
@classmethod
def resource_setup(cls):
super(ShareRulesTest, cls).resource_setup()
if not (any(p in CONF.share.enable_ip_rules_for_protocols
for p in cls.protocols) or
any(p in CONF.share.enable_user_rules_for_protocols
for p in cls.protocols) or
any(p in CONF.share.enable_cert_rules_for_protocols
for p in cls.protocols)):
cls.message = "Rule tests are disabled"
raise cls.skipException(cls.message)
cls.share = cls.create_share()
def setUp(self):
# Here we choose protocol and rule type for
# testing common rules functionality,
# that isn't dependent on protocol or rule type.
super(ShareRulesTest, self).setUp()
if CONF.share.enable_ip_rules_for_protocols:
self.access_type = "ip"
self.access_to = "8.8.8.8"
protocol = CONF.share.enable_ip_rules_for_protocols[0]
elif CONF.share.enable_user_rules_for_protocols:
self.access_type = "user"
self.access_to = CONF.share.username_for_user_rules
protocol = CONF.share.enable_user_rules_for_protocols[0]
elif CONF.share.enable_cert_rules_for_protocols:
self.access_type = "cert"
self.access_to = "client3.com"
protocol = CONF.share.enable_cert_rules_for_protocols[0]
else:
raise self.skipException(self.message)
self.shares_client.protocol = protocol
@test.attr(type=["gate", ])
def test_list_access_rules(self):
# create rule
rule = self.shares_client.create_access_rule(
self.share["id"], self.access_type, self.access_to)
self.shares_client.wait_for_access_rule_status(
self.share["id"], rule["id"], "active")
# list rules
rules = self.shares_client.list_access_rules(self.share["id"])
# verify keys
keys = ["state", "id", "access_type", "access_to", "access_level"]
[self.assertIn(key, r.keys()) for r in rules for key in keys]
# verify values
self.assertEqual("active", rules[0]["state"])
self.assertEqual(self.access_type, rules[0]["access_type"])
self.assertEqual(self.access_to, rules[0]["access_to"])
self.assertEqual('rw', rules[0]["access_level"])
# our share id in list and have no duplicates
gen = [r["id"] for r in rules if r["id"] in rule["id"]]
msg = "expected id lists %s times in rule list" % (len(gen))
self.assertEqual(len(gen), 1, msg)
@test.attr(type=["gate", ])
def test_access_rules_deleted_if_share_deleted(self):
# create share
share = self.create_share()
# create rule
rule = self.shares_client.create_access_rule(
share["id"], self.access_type, self.access_to)
self.shares_client.wait_for_access_rule_status(
share["id"], rule["id"], "active")
# delete share
self.shares_client.delete_share(share['id'])
self.shares_client.wait_for_resource_deletion(share_id=share['id'])
# verify absence of rules for nonexistent share id
self.assertRaises(lib_exc.NotFound,
self.shares_client.list_access_rules,
share['id'])

View File

@ -0,0 +1,299 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class ShareIpRulesForNFSNegativeTest(base.BaseSharesTest):
protocol = "nfs"
@classmethod
def resource_setup(cls):
super(ShareIpRulesForNFSNegativeTest, cls).resource_setup()
if not (cls.protocol in CONF.share.enable_protocols and
cls.protocol in CONF.share.enable_ip_rules_for_protocols):
msg = "IP rule tests for %s protocol are disabled" % cls.protocol
raise cls.skipException(msg)
# create share
cls.share = cls.create_share(cls.protocol)
if CONF.share.run_snapshot_tests:
# create snapshot
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_ip_with_wrong_target_1(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "ip", "1.2.3.256")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_ip_with_wrong_target_2(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "ip", "1.1.1.-")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_ip_with_wrong_target_3(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "ip", "1.2.3.4/33")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_ip_with_wrong_target_4(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "ip", "1.2.3.*")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_ip_with_wrong_target_5(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "ip", "1.2.3.*/23")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_ip_with_wrong_target_6(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "ip", "1.2.3.1|23")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_ip_with_wrong_target_7(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "ip", "1.2.3.1/-1")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_ip_with_wrong_target_8(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "ip", "1.2.3.1/")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_with_wrong_level(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"],
'ip',
'2.2.2.2',
'su')
@test.attr(type=["negative", "gate", ])
def test_create_duplicate_of_ip_rule(self):
# test data
access_type = "ip"
access_to = "1.2.3.4"
# create rule
rule = self.shares_client.create_access_rule(
self.share["id"], access_type, access_to)
self.shares_client.wait_for_access_rule_status(
self.share["id"], rule["id"], "active")
# try create duplicate of rule
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], access_type, access_to)
class ShareIpRulesForCIFSNegativeTest(ShareIpRulesForNFSNegativeTest):
protocol = "cifs"
class ShareUserRulesForNFSNegativeTest(base.BaseSharesTest):
protocol = "nfs"
@classmethod
def resource_setup(cls):
super(ShareUserRulesForNFSNegativeTest, cls).resource_setup()
if not (cls.protocol in CONF.share.enable_protocols and
cls.protocol in CONF.share.enable_user_rules_for_protocols):
msg = "USER rule tests for %s protocol are disabled" % cls.protocol
raise cls.skipException(msg)
# create share
cls.share = cls.create_share(cls.protocol)
if CONF.share.run_snapshot_tests:
# create snapshot
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_user_with_wrong_input_2(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "user",
"try+")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_user_with_empty_key(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "user", "")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_user_with_too_little_key(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "user", "abc")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_user_with_too_big_key(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "user", "a" * 33)
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_user_with_wrong_input_1(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "user",
"try+")
@test.attr(type=["negative", "gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_create_access_rule_user_to_snapshot(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.create_access_rule,
self.snap["id"],
access_type="user",
access_to="fakeuser")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_user_with_wrong_share_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.create_access_rule,
"wrong_share_id",
access_type="user",
access_to="fakeuser")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_with_wrong_level(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"],
'user',
CONF.share.username_for_user_rules,
'su')
class ShareUserRulesForCIFSNegativeTest(ShareUserRulesForNFSNegativeTest):
protocol = "cifs"
class ShareCertRulesForGLUSTERFSNegativeTest(base.BaseSharesTest):
protocol = "glusterfs"
@classmethod
def resource_setup(cls):
super(ShareCertRulesForGLUSTERFSNegativeTest, cls).resource_setup()
if not (cls.protocol in CONF.share.enable_protocols and
cls.protocol in CONF.share.enable_cert_rules_for_protocols):
msg = "CERT rule tests for %s protocol are disabled" % cls.protocol
raise cls.skipException(msg)
# create share
cls.share = cls.create_share(cls.protocol)
if CONF.share.run_snapshot_tests:
# create snapshot
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_cert_with_empty_common_name(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "cert", "")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_cert_with_whitespace_common_name(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "cert", " ")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_cert_with_too_big_common_name(self):
# common name cannot be more than 64 characters long
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "cert", "a" * 65)
@test.attr(type=["negative", "gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_create_access_rule_cert_to_snapshot(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.create_access_rule,
self.snap["id"],
access_type="cert",
access_to="fakeclient1.com")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_cert_with_wrong_share_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.create_access_rule,
"wrong_share_id",
access_type="cert",
access_to="fakeclient2.com")
class ShareRulesNegativeTest(base.BaseSharesTest):
# Tests independent from rule type and share protocol
@classmethod
def resource_setup(cls):
super(ShareRulesNegativeTest, cls).resource_setup()
if not (any(p in CONF.share.enable_ip_rules_for_protocols
for p in cls.protocols) or
any(p in CONF.share.enable_user_rules_for_protocols
for p in cls.protocols) or
any(p in CONF.share.enable_cert_rules_for_protocols
for p in cls.protocols)):
cls.message = "Rule tests are disabled"
raise cls.skipException(cls.message)
# create share
cls.share = cls.create_share()
if CONF.share.run_snapshot_tests:
# create snapshot
cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
@test.attr(type=["negative", "gate", ])
def test_delete_access_rule_with_wrong_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_access_rule,
self.share["id"], "wrong_rule_id")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_ip_with_wrong_type(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_access_rule,
self.share["id"], "wrong_type", "1.2.3.4")
@test.attr(type=["negative", "gate", ])
def test_create_access_rule_ip_with_wrong_share_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.create_access_rule,
"wrong_share_id")
@test.attr(type=["negative", "gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_create_access_rule_ip_to_snapshot(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.create_access_rule,
self.snap["id"])

View File

@ -0,0 +1,33 @@
# Copyright 2015 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
from manila_tempest_tests.tests.api import base
class SchedulerStatsNegativeTest(base.BaseSharesTest):
@test.attr(type=["gate", "smoke", "negative", ])
def test_try_list_pools_with_user(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.list_pools)
@test.attr(type=["gate", "smoke", "negative", ])
def test_try_list_pools_detailed_with_user(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.list_pools,
detail=True)

View File

@ -0,0 +1,202 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log # noqa
import six # noqa
from tempest import config # noqa
from tempest import test # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
LOG = log.getLogger(__name__)
class SecurityServiceListMixin(object):
@test.attr(type=["gate", "smoke"])
def test_list_security_services(self):
listed = self.shares_client.list_security_services()
self.assertTrue(any(self.ss_ldap['id'] == ss['id'] for ss in listed))
self.assertTrue(any(self.ss_kerberos['id'] == ss['id']
for ss in listed))
# verify keys
keys = ["name", "id", "status", "type", ]
[self.assertIn(key, s_s.keys()) for s_s in listed for key in keys]
@test.attr(type=["gate", "smoke"])
def test_list_security_services_with_detail(self):
listed = self.shares_client.list_security_services(detailed=True)
self.assertTrue(any(self.ss_ldap['id'] == ss['id'] for ss in listed))
self.assertTrue(any(self.ss_kerberos['id'] == ss['id']
for ss in listed))
# verify keys
keys = [
"name", "id", "status", "description",
"domain", "server", "dns_ip", "user", "password", "type",
"created_at", "updated_at", "project_id",
]
[self.assertIn(key, s_s.keys()) for s_s in listed for key in keys]
@test.attr(type=["gate", "smoke"])
@testtools.skipIf(
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
def test_list_security_services_filter_by_share_network(self):
sn = self.shares_client.get_share_network(
self.os.shares_client.share_network_id)
fresh_sn = []
for i in range(2):
sn = self.create_share_network(
neutron_net_id=sn["neutron_net_id"],
neutron_subnet_id=sn["neutron_subnet_id"])
fresh_sn.append(sn)
self.shares_client.add_sec_service_to_share_network(
fresh_sn[0]["id"], self.ss_ldap["id"])
self.shares_client.add_sec_service_to_share_network(
fresh_sn[1]["id"], self.ss_kerberos["id"])
listed = self.shares_client.list_security_services(
params={'share_network_id': fresh_sn[0]['id']})
self.assertEqual(1, len(listed))
self.assertEqual(self.ss_ldap['id'], listed[0]['id'])
keys = ["name", "id", "status", "type", ]
[self.assertIn(key, s_s.keys()) for s_s in listed for key in keys]
@test.attr(type=["gate", "smoke"])
def test_list_security_services_detailed_filter_by_ss_attributes(self):
search_opts = {
'name': 'ss_ldap',
'type': 'ldap',
'user': 'fake_user',
'server': 'fake_server_1',
'dns_ip': '1.1.1.1',
'domain': 'fake_domain_1',
}
listed = self.shares_client.list_security_services(
detailed=True,
params=search_opts)
self.assertTrue(any(self.ss_ldap['id'] == ss['id'] for ss in listed))
for ss in listed:
self.assertTrue(all(ss[key] == value for key, value
in six.iteritems(search_opts)))
class SecurityServicesTest(base.BaseSharesTest,
SecurityServiceListMixin):
def setUp(self):
super(SecurityServicesTest, self).setUp()
ss_ldap_data = {
'name': 'ss_ldap',
'dns_ip': '1.1.1.1',
'server': 'fake_server_1',
'domain': 'fake_domain_1',
'user': 'fake_user',
'password': 'pass',
}
ss_kerberos_data = {
'name': 'ss_kerberos',
'dns_ip': '2.2.2.2',
'server': 'fake_server_2',
'domain': 'fake_domain_2',
'user': 'test_user',
'password': 'word',
}
self.ss_ldap = self.create_security_service('ldap', **ss_ldap_data)
self.ss_kerberos = self.create_security_service(
'kerberos', **ss_kerberos_data)
@test.attr(type=["gate", "smoke"])
def test_create_delete_security_service(self):
data = self.generate_security_service_data()
self.service_names = ["ldap", "kerberos", "active_directory"]
for ss_name in self.service_names:
ss = self.create_security_service(ss_name, **data)
self.assertDictContainsSubset(data, ss)
self.assertEqual(ss_name, ss["type"])
self.shares_client.delete_security_service(ss["id"])
@test.attr(type=["gate", "smoke"])
def test_get_security_service(self):
data = self.generate_security_service_data()
ss = self.create_security_service(**data)
self.assertDictContainsSubset(data, ss)
get = self.shares_client.get_security_service(ss["id"])
self.assertDictContainsSubset(data, get)
@test.attr(type=["gate", "smoke"])
def test_update_security_service(self):
data = self.generate_security_service_data()
ss = self.create_security_service(**data)
self.assertDictContainsSubset(data, ss)
upd_data = self.generate_security_service_data()
updated = self.shares_client.update_security_service(
ss["id"], **upd_data)
get = self.shares_client.get_security_service(ss["id"])
self.assertDictContainsSubset(upd_data, updated)
self.assertDictContainsSubset(upd_data, get)
@test.attr(type=["gate", "smoke"])
@testtools.skipIf(
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
def test_try_update_valid_keys_sh_server_exists(self):
ss_data = self.generate_security_service_data()
ss = self.create_security_service(**ss_data)
sn = self.shares_client.get_share_network(
self.os.shares_client.share_network_id)
fresh_sn = self.create_share_network(
neutron_net_id=sn["neutron_net_id"],
neutron_subnet_id=sn["neutron_subnet_id"])
self.shares_client.add_sec_service_to_share_network(
fresh_sn["id"], ss["id"])
# Security service with fake data is used, so if we use backend driver
# that fails on wrong data, we expect error here.
# We require any share that uses our share-network.
try:
self.create_share(
share_network_id=fresh_sn["id"], cleanup_in_class=False)
except Exception as e:
# we do wait for either 'error' or 'available' status because
# it is the only available statuses for proper deletion.
LOG.warning("Caught exception. It is expected in case backend "
"fails having security-service with improper data "
"that leads to share-server creation error. "
"%s" % six.text_type(e))
update_data = {
"name": "name",
"description": "new_description",
}
updated = self.shares_client.update_security_service(
ss["id"], **update_data)
self.assertDictContainsSubset(update_data, updated)
@test.attr(type=["gate", "smoke"])
def test_list_security_services_filter_by_invalid_opt(self):
listed = self.shares_client.list_security_services(
params={'fake_opt': 'some_value'})
self.assertTrue(any(self.ss_ldap['id'] == ss['id'] for ss in listed))
self.assertTrue(any(self.ss_kerberos['id'] == ss['id']
for ss in listed))

View File

@ -0,0 +1,70 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import test # noqa
from manila_tempest_tests.tests.api import base
class SecurityServicesMappingTest(base.BaseSharesTest):
@classmethod
def resource_setup(cls):
super(SecurityServicesMappingTest, cls).resource_setup()
cls.cl = cls.shares_client
def setUp(self):
super(SecurityServicesMappingTest, self).setUp()
# create share network
data = self.generate_share_network_data()
self.sn = self.create_share_network(client=self.cl, **data)
self.assertDictContainsSubset(data, self.sn)
# create security service
data = self.generate_security_service_data()
self.ss = self.create_security_service(client=self.cl, **data)
self.assertDictContainsSubset(data, self.ss)
# Add security service to share network
self.cl.add_sec_service_to_share_network(self.sn["id"], self.ss["id"])
@test.attr(type=["gate", "smoke"])
def test_map_ss_to_sn_and_list(self):
# List security services for share network
ls = self.cl.list_sec_services_for_share_network(self.sn["id"])
self.assertEqual(1, len(ls))
for key in ["status", "id", "name"]:
self.assertIn(self.ss[key], ls[0][key])
@test.attr(type=["gate", "smoke"])
def test_map_ss_to_sn_and_delete(self):
# Remove security service from share network
self.cl.remove_sec_service_from_share_network(
self.sn["id"], self.ss["id"])
@test.attr(type=["gate", "smoke"])
def test_remap_ss_to_sn(self):
# Remove security service from share network
self.cl.remove_sec_service_from_share_network(
self.sn["id"], self.ss["id"])
# Add security service to share network again
self.cl.add_sec_service_to_share_network(self.sn["id"], self.ss["id"])

View File

@ -0,0 +1,157 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class SecServicesMappingNegativeTest(base.BaseSharesTest):
@classmethod
def resource_setup(cls):
super(SecServicesMappingNegativeTest, cls).resource_setup()
cls.sn = cls.create_share_network(cleanup_in_class=True)
cls.ss = cls.create_security_service(cleanup_in_class=True)
cls.cl = cls.shares_client
@test.attr(type=["gate", "smoke", "negative"])
def test_add_sec_service_twice_to_share_network(self):
self.cl.add_sec_service_to_share_network(self.sn["id"], self.ss["id"])
self.assertRaises(lib_exc.Conflict,
self.cl.add_sec_service_to_share_network,
self.sn["id"], self.ss["id"])
@test.attr(type=["gate", "smoke", "negative"])
def test_add_nonexistant_sec_service_to_share_network(self):
self.assertRaises(lib_exc.NotFound,
self.cl.add_sec_service_to_share_network,
self.sn["id"], "wrong_ss_id")
@test.attr(type=["gate", "smoke", "negative"])
def test_add_empty_sec_service_id_to_share_network(self):
self.assertRaises(lib_exc.NotFound,
self.cl.add_sec_service_to_share_network,
self.sn["id"], "")
@test.attr(type=["gate", "smoke", "negative"])
def test_add_sec_service_to_nonexistant_share_network(self):
self.assertRaises(lib_exc.NotFound,
self.cl.add_sec_service_to_share_network,
"wrong_sn_id", self.ss["id"])
@test.attr(type=["gate", "smoke", "negative"])
def test_add_sec_service_to_share_network_with_empty_id(self):
self.assertRaises(lib_exc.NotFound,
self.cl.add_sec_service_to_share_network,
"", self.ss["id"])
@test.attr(type=["gate", "smoke", "negative"])
def test_list_sec_services_for_nonexistant_share_network(self):
self.assertRaises(lib_exc.NotFound,
self.cl.list_sec_services_for_share_network,
"wrong_id")
@test.attr(type=["gate", "smoke", "negative"])
def test_delete_nonexistant_sec_service_from_share_network(self):
self.assertRaises(lib_exc.NotFound,
self.cl.remove_sec_service_from_share_network,
self.sn["id"], "wrong_id")
@test.attr(type=["gate", "smoke", "negative"])
def test_delete_sec_service_from_nonexistant_share_network(self):
self.assertRaises(lib_exc.NotFound,
self.cl.remove_sec_service_from_share_network,
"wrong_id", self.ss["id"])
@test.attr(type=["gate", "smoke", "negative"])
def test_delete_nonexistant_ss_from_nonexistant_sn(self):
self.assertRaises(lib_exc.NotFound,
self.cl.remove_sec_service_from_share_network,
"wrong_id", "wrong_id")
@test.attr(type=["gate", "smoke", "negative"])
@testtools.skipIf(
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
def test_delete_ss_from_sn_used_by_share_server(self):
sn = self.shares_client.get_share_network(
self.os.shares_client.share_network_id)
fresh_sn = self.create_share_network(
neutron_net_id=sn["neutron_net_id"],
neutron_subnet_id=sn["neutron_subnet_id"])
self.shares_client.add_sec_service_to_share_network(
fresh_sn["id"], self.ss["id"])
self.create_share(
share_network_id=fresh_sn["id"], cleanup_in_class=False)
self.assertRaises(lib_exc.Forbidden,
self.cl.remove_sec_service_from_share_network,
fresh_sn["id"],
self.ss["id"])
@test.attr(type=["gate", "smoke", "negative"])
def test_try_map_two_ss_with_same_type_to_sn(self):
# create share network
data = self.generate_share_network_data()
sn = self.create_share_network(client=self.cl, **data)
self.assertDictContainsSubset(data, sn)
# create security services with same type
security_services = []
for i in range(2):
data = self.generate_security_service_data()
ss = self.create_security_service(client=self.cl, **data)
self.assertDictContainsSubset(data, ss)
security_services.insert(i, ss)
# Add security service to share network
self.cl.add_sec_service_to_share_network(
sn["id"], security_services[0]["id"])
# Try to add security service with same type
self.assertRaises(lib_exc.Conflict,
self.cl.add_sec_service_to_share_network,
sn["id"], security_services[1]["id"])
@test.attr(type=["gate", "smoke", "negative"])
def test_try_delete_ss_that_assigned_to_sn(self):
# create share network
data = self.generate_share_network_data()
sn = self.create_share_network(client=self.cl, **data)
self.assertDictContainsSubset(data, sn)
# create security service
data = self.generate_security_service_data()
ss = self.create_security_service(client=self.cl, **data)
self.assertDictContainsSubset(data, ss)
# Add security service to share network
self.cl.add_sec_service_to_share_network(sn["id"], ss["id"])
# Try delete ss, that has been assigned to some sn
self.assertRaises(lib_exc.Forbidden,
self.cl.delete_security_service,
ss["id"], )
# remove seurity service from share-network
self.cl.remove_sec_service_from_share_network(sn["id"], ss["id"])

View File

@ -0,0 +1,128 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log # noqa
import six # noqa
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
LOG = log.getLogger(__name__)
class SecurityServicesNegativeTest(base.BaseSharesTest):
@test.attr(type=["gate", "smoke", "negative"])
def test_try_create_security_service_with_empty_type(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_security_service, "")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_create_security_service_with_wrong_type(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_security_service,
"wrong_type")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_get_security_service_without_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_security_service, "")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_get_security_service_with_wrong_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_security_service,
"wrong_id")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_delete_security_service_without_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_security_service, "")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_delete_security_service_with_wrong_type(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_security_service,
"wrong_id")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_update_nonexistant_security_service(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.update_security_service,
"wrong_id", name="name")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_update_security_service_with_empty_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.update_security_service,
"", name="name")
@test.attr(type=["gate", "smoke", "negative"])
@testtools.skipIf(
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
def test_try_update_invalid_keys_sh_server_exists(self):
ss_data = self.generate_security_service_data()
ss = self.create_security_service(**ss_data)
sn = self.shares_client.get_share_network(
self.os.shares_client.share_network_id)
fresh_sn = self.create_share_network(
neutron_net_id=sn["neutron_net_id"],
neutron_subnet_id=sn["neutron_subnet_id"])
self.shares_client.add_sec_service_to_share_network(
fresh_sn["id"], ss["id"])
# Security service with fake data is used, so if we use backend driver
# that fails on wrong data, we expect error here.
# We require any share that uses our share-network.
try:
self.create_share(
share_network_id=fresh_sn["id"], cleanup_in_class=False)
except Exception as e:
# we do wait for either 'error' or 'available' status because
# it is the only available statuses for proper deletion.
LOG.warning("Caught exception. It is expected in case backend "
"fails having security-service with improper data "
"that leads to share-server creation error. "
"%s" % six.text_type(e))
self.assertRaises(lib_exc.Forbidden,
self.shares_client.update_security_service,
ss["id"],
user="new_user")
@test.attr(type=["gate", "smoke", "negative"])
def test_get_deleted_security_service(self):
data = self.generate_security_service_data()
ss = self.create_security_service(**data)
self.assertDictContainsSubset(data, ss)
self.shares_client.delete_security_service(ss["id"])
# try get deleted security service entity
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_security_service,
ss["id"])
@test.attr(type=["gate", "smoke", "negative"])
def test_try_list_security_services_all_tenants(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.list_security_services,
params={'all_tenants': 1})

View File

@ -0,0 +1,216 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import six # noqa
from tempest import config # noqa
from tempest import test # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class ShareNetworkListMixin(object):
@test.attr(type=["gate", "smoke", ])
def test_list_share_networks(self):
listed = self.shares_client.list_share_networks()
any(self.sn_with_ldap_ss["id"] in sn["id"] for sn in listed)
# verify keys
keys = ["name", "id"]
[self.assertIn(key, sn.keys()) for sn in listed for key in keys]
@test.attr(type=["gate", "smoke", ])
def test_list_share_networks_with_detail(self):
listed = self.shares_client.list_share_networks_with_detail()
any(self.sn_with_ldap_ss["id"] in sn["id"] for sn in listed)
# verify keys
keys = [
"name", "id", "description", "network_type",
"project_id", "cidr", "ip_version",
"neutron_net_id", "neutron_subnet_id",
"created_at", "updated_at", "segmentation_id",
]
[self.assertIn(key, sn.keys()) for sn in listed for key in keys]
@test.attr(type=["gate", "smoke", ])
def test_list_share_networks_filter_by_ss(self):
listed = self.shares_client.list_share_networks_with_detail(
{'security_service_id': self.ss_ldap['id']})
self.assertTrue(any(self.sn_with_ldap_ss['id'] == sn['id']
for sn in listed))
for sn in listed:
ss_list = self.shares_client.list_sec_services_for_share_network(
sn['id'])
self.assertTrue(any(ss['id'] == self.ss_ldap['id']
for ss in ss_list))
@test.attr(type=["gate", "smoke", ])
def test_list_share_networks_all_filter_opts(self):
valid_filter_opts = {
'created_before': '2002-10-10',
'created_since': '2001-01-01',
'neutron_net_id': '1111',
'neutron_subnet_id': '2222',
'network_type': 'vlan',
'segmentation_id': 1000,
'cidr': '10.0.0.0/24',
'ip_version': 4,
'name': 'sn_with_ldap_ss'
}
listed = self.shares_client.list_share_networks_with_detail(
valid_filter_opts)
self.assertTrue(any(self.sn_with_ldap_ss['id'] == sn['id']
for sn in listed))
created_before = valid_filter_opts.pop('created_before')
created_since = valid_filter_opts.pop('created_since')
for sn in listed:
self.assertTrue(all(sn[key] == value for key, value in
six.iteritems(valid_filter_opts)))
self.assertTrue(sn['created_at'] <= created_before)
self.assertTrue(sn['created_at'] >= created_since)
class ShareNetworksTest(base.BaseSharesTest, ShareNetworkListMixin):
@classmethod
def resource_setup(cls):
super(ShareNetworksTest, cls).resource_setup()
ss_data = cls.generate_security_service_data()
cls.ss_ldap = cls.create_security_service(**ss_data)
cls.data_sn_with_ldap_ss = {
'name': 'sn_with_ldap_ss',
'neutron_net_id': '1111',
'neutron_subnet_id': '2222',
'created_at': '2002-02-02',
'updated_at': None,
'network_type': 'vlan',
'segmentation_id': 1000,
'cidr': '10.0.0.0/24',
'ip_version': 4,
'description': 'fake description',
}
cls.sn_with_ldap_ss = cls.create_share_network(
cleanup_in_class=True,
**cls.data_sn_with_ldap_ss)
cls.shares_client.add_sec_service_to_share_network(
cls.sn_with_ldap_ss["id"],
cls.ss_ldap["id"])
cls.data_sn_with_kerberos_ss = {
'name': 'sn_with_kerberos_ss',
'neutron_net_id': '3333',
'neutron_subnet_id': '4444',
'created_at': '2003-03-03',
'updated_at': None,
'neutron_net_id': 'test net id',
'neutron_subnet_id': 'test subnet id',
'network_type': 'local',
'segmentation_id': 2000,
'cidr': '10.0.0.0/13',
'ip_version': 6,
'description': 'fake description',
}
cls.ss_kerberos = cls.create_security_service(
ss_type='kerberos',
**cls.data_sn_with_ldap_ss)
cls.sn_with_kerberos_ss = cls.create_share_network(
cleanup_in_class=True,
**cls.data_sn_with_kerberos_ss)
cls.shares_client.add_sec_service_to_share_network(
cls.sn_with_kerberos_ss["id"],
cls.ss_kerberos["id"])
@test.attr(type=["gate", "smoke", ])
def test_create_delete_share_network(self):
# generate data for share network
data = self.generate_share_network_data()
# create share network
created = self.shares_client.create_share_network(**data)
self.assertDictContainsSubset(data, created)
# Delete share_network
self.shares_client.delete_share_network(created["id"])
@test.attr(type=["gate", "smoke", ])
def test_get_share_network(self):
get = self.shares_client.get_share_network(self.sn_with_ldap_ss["id"])
self.assertEqual('2002-02-02T00:00:00.000000', get['created_at'])
data = self.data_sn_with_ldap_ss.copy()
del data['created_at']
self.assertDictContainsSubset(data, get)
@test.attr(type=["gate", "smoke", ])
def test_update_share_network(self):
update_data = self.generate_share_network_data()
updated = self.shares_client.update_share_network(
self.sn_with_ldap_ss["id"],
**update_data)
self.assertDictContainsSubset(update_data, updated)
@test.attr(type=["gate", "smoke"])
@testtools.skipIf(
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
def test_update_valid_keys_sh_server_exists(self):
self.create_share(cleanup_in_class=False)
update_dict = {
"name": "new_name",
"description": "new_description",
}
updated = self.shares_client.update_share_network(
self.shares_client.share_network_id, **update_dict)
self.assertDictContainsSubset(update_dict, updated)
@test.attr(type=["gate", "smoke", ])
def test_recreate_share_network(self):
# generate data for share network
data = self.generate_share_network_data()
# create share network
sn1 = self.shares_client.create_share_network(**data)
self.assertDictContainsSubset(data, sn1)
# Delete first share network
self.shares_client.delete_share_network(sn1["id"])
# create second share network with same data
sn2 = self.shares_client.create_share_network(**data)
self.assertDictContainsSubset(data, sn2)
# Delete second share network
self.shares_client.delete_share_network(sn2["id"])
@test.attr(type=["gate", "smoke", ])
def test_create_two_share_networks_with_same_net_and_subnet(self):
# generate data for share network
data = self.generate_share_network_data()
# create first share network
sn1 = self.create_share_network(**data)
self.assertDictContainsSubset(data, sn1)
# create second share network
sn2 = self.create_share_network(**data)
self.assertDictContainsSubset(data, sn2)

View File

@ -0,0 +1,131 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class ShareNetworksNegativeTest(base.BaseSharesTest):
@test.attr(type=["gate", "smoke", "negative"])
def test_try_get_share_network_without_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share_network, "")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_get_share_network_with_wrong_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share_network, "wrong_id")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_delete_share_network_without_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_share_network, "")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_delete_share_network_with_wrong_type(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_share_network, "wrong_id")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_update_nonexistant_share_network(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.update_share_network,
"wrong_id", name="name")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_update_share_network_with_empty_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.update_share_network,
"", name="name")
@test.attr(type=["gate", "smoke", "negative"])
@testtools.skipIf(
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
def test_try_update_invalid_keys_sh_server_exists(self):
self.create_share(cleanup_in_class=False)
self.assertRaises(lib_exc.Forbidden,
self.shares_client.update_share_network,
self.shares_client.share_network_id,
neutron_net_id="new_net_id")
@test.attr(type=["gate", "smoke", "negative"])
def test_try_get_deleted_share_network(self):
data = self.generate_share_network_data()
sn = self.create_share_network(**data)
self.assertDictContainsSubset(data, sn)
self.shares_client.delete_share_network(sn["id"])
# try get deleted share network entity
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_security_service,
sn["id"])
@test.attr(type=["gate", "smoke", "negative"])
def test_try_list_share_networks_all_tenants(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.list_share_networks_with_detail,
params={'all_tenants': 1})
@test.attr(type=["gate", "smoke", "negative"])
def test_try_list_share_networks_project_id(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.list_share_networks_with_detail,
params={'project_id': 'some_project'})
@test.attr(type=["gate", "smoke", "negative"])
def test_try_list_share_networks_wrong_created_since_value(self):
self.assertRaises(
lib_exc.BadRequest,
self.shares_client.list_share_networks_with_detail,
params={'created_since': '2014-10-23T08:31:58.000000'})
@test.attr(type=["gate", "smoke", "negative"])
def test_try_list_share_networks_wrong_created_before_value(self):
self.assertRaises(
lib_exc.BadRequest,
self.shares_client.list_share_networks_with_detail,
params={'created_before': '2014-10-23T08:31:58.000000'})
@test.attr(type=["gate", "smoke", "negative"])
@testtools.skipIf(not CONF.share.multitenancy_enabled,
'Can run only with drivers that do handle share servers '
'creation. Skipping.')
def test_try_delete_share_network_with_existing_shares(self):
# Get valid network data for successful share creation
share_network = self.shares_client.get_share_network(
self.shares_client.share_network_id)
new_sn = self.create_share_network(
neutron_net_id=share_network['neutron_net_id'],
neutron_subnet_id=share_network['neutron_subnet_id'],
nova_net_id=share_network['nova_net_id'],
cleanup_in_class=False)
# Create share with share network
self.create_share(
share_network_id=new_sn['id'], cleanup_in_class=False)
# Try delete share network
self.assertRaises(
lib_exc.Conflict,
self.shares_client.delete_share_network, new_sn['id'])

View File

@ -0,0 +1,64 @@
# Copyright 2014 OpenStack Foundation
# 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 test # noqa
from tempest_lib.common.utils import data_utils # noqa
from tempest_lib import exceptions as lib_exc # noqa
from manila_tempest_tests import clients_share as clients
from manila_tempest_tests.tests.api import base
class ShareTypesNegativeTest(base.BaseSharesTest):
@classmethod
def _create_share_type(cls):
name = data_utils.rand_name("unique_st_name")
extra_specs = cls.add_required_extra_specs_to_dict()
return cls.create_share_type(
name, extra_specs=extra_specs,
client=clients.AdminManager().shares_client)
@classmethod
def resource_setup(cls):
super(ShareTypesNegativeTest, cls).resource_setup()
cls.st = cls._create_share_type()
@test.attr(type=["gate", "smoke", "negative"])
def test_try_create_share_type_with_user(self):
self.assertRaises(lib_exc.Forbidden,
self.create_share_type,
data_utils.rand_name("used_user_creds"),
client=self.shares_client)
@test.attr(type=["gate", "smoke", "negative"])
def test_try_delete_share_type_with_user(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.delete_share_type,
self.st["share_type"]["id"])
@test.attr(type=["gate", "smoke", "negative"])
def test_try_add_access_to_share_type_with_user(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.add_access_to_share_type,
self.st['share_type']['id'],
self.shares_client.tenant_id)
@test.attr(type=["gate", "smoke", "negative"])
def test_try_remove_access_from_share_type_with_user(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.remove_access_from_share_type,
self.st['share_type']['id'],
self.shares_client.tenant_id)

View File

@ -0,0 +1,150 @@
# Copyright 2014 mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class SharesNFSTest(base.BaseSharesTest):
"""Covers share functionality, that is related to NFS share type."""
protocol = "nfs"
@classmethod
def resource_setup(cls):
super(SharesNFSTest, cls).resource_setup()
if cls.protocol not in CONF.share.enable_protocols:
message = "%s tests are disabled" % cls.protocol
raise cls.skipException(message)
cls.share = cls.create_share(cls.protocol)
@test.attr(type=["gate", ])
def test_create_delete_share(self):
# create share
share = self.create_share(self.protocol)
detailed_elements = {'name', 'id', 'availability_zone',
'description', 'export_location', 'project_id',
'host', 'created_at', 'share_proto', 'metadata',
'size', 'snapshot_id', 'share_network_id',
'status', 'share_type', 'volume_type', 'links',
'is_public'}
self.assertTrue(detailed_elements.issubset(share.keys()),
'At least one expected element missing from share '
'response. Expected %(expected)s, got %(actual)s.' % {
"expected": detailed_elements,
"actual": share.keys()})
self.assertFalse(share['is_public'])
# delete share
self.shares_client.delete_share(share['id'])
self.shares_client.wait_for_resource_deletion(share_id=share['id'])
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share,
share['id'])
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_create_delete_snapshot(self):
# create snapshot
snap = self.create_snapshot_wait_for_active(self.share["id"])
detailed_elements = {'name', 'id', 'description',
'created_at', 'share_proto', 'size', 'share_size',
'share_id', 'status', 'links'}
self.assertTrue(detailed_elements.issubset(snap.keys()),
'At least one expected element missing from snapshot '
'response. Expected %(expected)s, got %(actual)s.' % {
"expected": detailed_elements,
"actual": snap.keys()})
# delete snapshot
self.shares_client.delete_snapshot(snap["id"])
self.shares_client.wait_for_resource_deletion(snapshot_id=snap["id"])
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_snapshot, snap['id'])
@test.attr(type=["gate", "smoke", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_create_share_from_snapshot(self):
# If multitenant driver used, share_network will be provided by default
# create snapshot
snap = self.create_snapshot_wait_for_active(
self.share["id"], cleanup_in_class=False)
# create share from snapshot
s2 = self.create_share(
self.protocol, snapshot_id=snap["id"], cleanup_in_class=False)
# verify share, created from snapshot
get = self.shares_client.get_share(s2["id"])
msg = "Expected snapshot_id %s as "\
"source of share %s" % (snap["id"], get["snapshot_id"])
self.assertEqual(get["snapshot_id"], snap["id"], msg)
@test.attr(type=["gate", "smoke", ])
@testtools.skipIf(not CONF.share.multitenancy_enabled,
"Only for multitenancy.")
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_create_share_from_snapshot_share_network_not_provided(self):
# We expect usage of share network from parent's share
# when creating share from snapshot using multitenant driver.
# get parent share
parent = self.shares_client.get_share(self.share["id"])
# create snapshot
snap = self.create_snapshot_wait_for_active(
self.share["id"], cleanup_in_class=False)
# create share from snapshot
child = self.create_share(
self.protocol, snapshot_id=snap["id"], cleanup_in_class=False)
# verify share, created from snapshot
get = self.shares_client.get_share(child["id"])
keys = {
"share": self.share["id"],
"actual_sn": get["share_network_id"],
"expected_sn": parent["share_network_id"],
}
msg = ("Expected share_network_id %(expected_sn)s for"
"share %(share)s, but %(actual_sn)s found." % keys)
self.assertEqual(
get["share_network_id"], parent["share_network_id"], msg)
class SharesCIFSTest(SharesNFSTest):
"""Covers share functionality, that is related to CIFS share type."""
protocol = "cifs"
class SharesGLUSTERFSTest(SharesNFSTest):
"""Covers share functionality that is related to GLUSTERFS share type."""
protocol = "glusterfs"
class SharesHDFSTest(SharesNFSTest):
"""Covers share functionality that is related to HDFS share type."""
protocol = "hdfs"

View File

@ -0,0 +1,507 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib.common.utils import data_utils # noqa
import testtools # noqa
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class SharesActionsTest(base.BaseSharesTest):
"""Covers share functionality, that doesn't related to share type."""
@classmethod
def resource_setup(cls):
super(SharesActionsTest, cls).resource_setup()
cls.shares = []
# create share
cls.share_name = data_utils.rand_name("tempest-share-name")
cls.share_desc = data_utils.rand_name("tempest-share-description")
cls.metadata = {
'foo_key_share_1': 'foo_value_share_1',
'bar_key_share_1': 'foo_value_share_1',
}
cls.share_size = 1
cls.shares.append(cls.create_share(
name=cls.share_name,
description=cls.share_desc,
size=cls.share_size,
metadata=cls.metadata,
))
if CONF.share.run_snapshot_tests:
# create snapshot
cls.snap_name = data_utils.rand_name("tempest-snapshot-name")
cls.snap_desc = data_utils.rand_name(
"tempest-snapshot-description")
cls.snap = cls.create_snapshot_wait_for_active(
cls.shares[0]["id"], cls.snap_name, cls.snap_desc)
# create second share from snapshot for purposes of sorting and
# snapshot filtering
cls.share_name2 = data_utils.rand_name("tempest-share-name")
cls.share_desc2 = data_utils.rand_name("tempest-share-description")
cls.metadata2 = {
'foo_key_share_2': 'foo_value_share_2',
'bar_key_share_2': 'foo_value_share_2',
}
cls.shares.append(cls.create_share(
name=cls.share_name2,
description=cls.share_desc2,
size=cls.share_size,
metadata=cls.metadata2,
snapshot_id=cls.snap['id'],
))
@test.attr(type=["gate", ])
def test_get_share(self):
# get share
share = self.shares_client.get_share(self.shares[0]['id'])
# verify keys
expected_keys = ["status", "description", "links", "availability_zone",
"created_at", "export_location", "share_proto",
"name", "snapshot_id", "id", "size"]
actual_keys = share.keys()
[self.assertIn(key, actual_keys) for key in expected_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)
@test.attr(type=["gate", ])
def test_list_shares(self):
# list shares
shares = self.shares_client.list_shares()
# verify keys
keys = ["name", "id", "links"]
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
# our share id in list and have no duplicates
for share in self.shares:
gen = [sid["id"] for sid in shares if sid["id"] in share["id"]]
msg = "expected id lists %s times in share list" % (len(gen))
self.assertEqual(1, len(gen), msg)
@test.attr(type=["gate", ])
def test_list_shares_with_detail(self):
# list shares
shares = self.shares_client.list_shares_with_detail()
# verify keys
keys = [
"status", "description", "links", "availability_zone",
"created_at", "export_location", "share_proto", "host",
"name", "snapshot_id", "id", "size", "project_id",
]
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
# our shares in list and have no duplicates
for share in self.shares:
gen = [sid["id"] for sid in shares if sid["id"] in share["id"]]
msg = "expected id lists %s times in share list" % (len(gen))
self.assertEqual(1, len(gen), msg)
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_metadata(self):
filters = {'metadata': self.metadata}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
for share in shares:
self.assertDictContainsSubset(
filters['metadata'], share['metadata'])
if CONF.share.run_snapshot_tests:
self.assertFalse(self.shares[1]['id'] in [s['id'] for s in shares])
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_host(self):
base_share = self.shares_client.get_share(self.shares[0]['id'])
filters = {'host': base_share['host']}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
for share in shares:
self.assertEqual(filters['host'], share['host'])
@test.attr(type=["gate", ])
@testtools.skipIf(
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
def test_list_shares_with_detail_filter_by_share_network_id(self):
base_share = self.shares_client.get_share(self.shares[0]['id'])
filters = {'share_network_id': base_share['share_network_id']}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
for share in shares:
self.assertEqual(
filters['share_network_id'], share['share_network_id'])
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_list_shares_with_detail_filter_by_snapshot_id(self):
filters = {'snapshot_id': self.snap['id']}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
for share in shares:
self.assertEqual(filters['snapshot_id'], share['snapshot_id'])
self.assertFalse(self.shares[0]['id'] in [s['id'] for s in shares])
@test.attr(type=["gate", ])
def test_list_shares_with_detail_with_asc_sorting(self):
filters = {'sort_key': 'created_at', 'sort_dir': 'asc'}
# list shares
shares = self.shares_client.list_shares_with_detail(params=filters)
# verify response
self.assertTrue(len(shares) > 0)
sorted_list = [share['created_at'] for share in shares]
self.assertEqual(sorted_list, sorted(sorted_list))
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_existed_name(self):
# list shares by name, at least one share is expected
params = {"name": self.share_name}
shares = self.shares_client.list_shares_with_detail(params)
self.assertEqual(shares[0]["name"], self.share_name)
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_fake_name(self):
# list shares by fake name, no shares are expected
params = {"name": data_utils.rand_name("fake-nonexistent-name")}
shares = self.shares_client.list_shares_with_detail(params)
self.assertEqual(len(shares), 0)
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_active_status(self):
# list shares by active status, at least one share is expected
params = {"status": "available"}
shares = self.shares_client.list_shares_with_detail(params)
self.assertTrue(len(shares) > 0)
for share in shares:
self.assertEqual(share["status"], params["status"])
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_fake_status(self):
# list shares by fake status, no shares are expected
params = {"status": 'fake'}
shares = self.shares_client.list_shares_with_detail(params)
self.assertEqual(len(shares), 0)
@test.attr(type=["gate", ])
def test_list_shares_with_detail_filter_by_all_tenants(self):
# non-admin user can get shares only from his project
params = {"all_tenants": 1}
shares = self.shares_client.list_shares_with_detail(params)
self.assertTrue(len(shares) > 0)
# get share with detailed info, we need its 'project_id'
share = self.shares_client.get_share(self.shares[0]["id"])
project_id = share["project_id"]
for share in shares:
self.assertEqual(share["project_id"], project_id)
@test.attr(type=["gate", ])
def test_list_shares_public_with_detail(self):
public_share = self.create_share(
name='public_share',
description='public_share_desc',
size=1,
is_public=True,
cleanup_in_class=False
)
private_share = self.create_share(
name='private_share',
description='private_share_desc',
size=1,
is_public=False,
cleanup_in_class=False
)
params = {"is_public": True}
isolated_client = self.get_client_with_isolated_creds(
type_of_creds='alt')
shares = isolated_client.list_shares_with_detail(params)
keys = [
"status", "description", "links", "availability_zone",
"created_at", "export_location", "share_proto", "host",
"name", "snapshot_id", "id", "size", "project_id", "is_public",
]
[self.assertIn(key, sh.keys()) for sh in shares for key in keys]
gen = [sid["id"] for sid in shares if sid["id"] == public_share["id"]]
msg = "expected id lists %s times in share list" % (len(gen))
self.assertEqual(1, len(gen), msg)
self.assertFalse(any([s["id"] == private_share["id"] for s in shares]))
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_get_snapshot(self):
# get snapshot
get = self.shares_client.get_snapshot(self.snap["id"])
# verify keys
expected_keys = ["status", "links", "share_id", "name",
"share_proto", "created_at",
"description", "id", "share_size"]
actual_keys = get.keys()
[self.assertIn(key, actual_keys) for key in expected_keys]
# verify data
msg = "Expected name: '%s', actual name: '%s'" % (self.snap_name,
get["name"])
self.assertEqual(self.snap_name, get["name"], msg)
msg = "Expected description: '%s', "\
"actual description: '%s'" % (self.snap_desc, get["description"])
self.assertEqual(self.snap_desc, get["description"], msg)
msg = "Expected share_id: '%s', "\
"actual share_id: '%s'" % (self.shares[0]["id"], get["share_id"])
self.assertEqual(self.shares[0]["id"], get["share_id"], msg)
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_list_snapshots(self):
# list share snapshots
snaps = self.shares_client.list_snapshots()
# verify keys
keys = ["id", "name", "links"]
[self.assertIn(key, sn.keys()) for sn in snaps for key in keys]
# our share id in list and have no duplicates
gen = [sid["id"] for sid in snaps if sid["id"] in self.snap["id"]]
msg = "expected id lists %s times in share list" % (len(gen))
self.assertEqual(1, len(gen), msg)
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_list_snapshots_with_detail(self):
# list share snapshots
snaps = self.shares_client.list_snapshots_with_detail()
# verify keys
keys = ["status", "links", "share_id", "name",
"share_proto", "created_at",
"description", "id", "share_size"]
[self.assertIn(key, sn.keys()) for sn in snaps for key in keys]
# our share id in list and have no duplicates
gen = [sid["id"] for sid in snaps if sid["id"] in self.snap["id"]]
msg = "expected id lists %s times in share list" % (len(gen))
self.assertEqual(len(gen), 1, msg)
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_list_snapshots_with_detail_use_limit(self):
for l, o in [('1', '1'), ('0', '1')]:
filters = {
'limit': l,
'offset': o,
'share_id': self.shares[0]['id'],
}
# list snapshots
snaps = self.shares_client.list_snapshots_with_detail(
params=filters)
# Our snapshot should not be listed
self.assertEqual(0, len(snaps))
# Only our one snapshot should be listed
snaps = self.shares_client.list_snapshots_with_detail(
params={'limit': '1', 'offset': '0',
'share_id': self.shares[0]['id']})
self.assertEqual(1, len(snaps['snapshots']))
self.assertEqual(self.snap['id'], snaps['snapshots'][0]['id'])
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_list_snapshots_with_detail_filter_by_status_and_name(self):
filters = {'status': 'available', 'name': self.snap_name}
# list snapshots
snaps = self.shares_client.list_snapshots_with_detail(
params=filters)
# verify response
self.assertTrue(len(snaps) > 0)
for snap in snaps:
self.assertEqual(filters['status'], snap['status'])
self.assertEqual(filters['name'], snap['name'])
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_list_snapshots_with_detail_and_asc_sorting(self):
filters = {'sort_key': 'share_id', 'sort_dir': 'asc'}
# list snapshots
snaps = self.shares_client.list_snapshots_with_detail(
params=filters)
# verify response
self.assertTrue(len(snaps) > 0)
sorted_list = [snap['share_id'] for snap in snaps]
self.assertEqual(sorted_list, sorted(sorted_list))
@test.attr(type=["gate", ])
@testtools.skipUnless(
CONF.share.run_extend_tests,
"Share extend tests are disabled.")
def test_extend_share(self):
share = self.create_share(size=1, cleanup_in_class=False)
new_size = 2
# extend share and wait for active status
self.shares_client.extend_share(share['id'], new_size)
self.shares_client.wait_for_share_status(share['id'], 'available')
# check state and new size
share = self.shares_client.get_share(share['id'])
self.assertEqual(new_size, share['size'])
@test.attr(type=["gate", ])
@testtools.skipUnless(
CONF.share.run_shrink_tests,
"Share shrink tests are disabled.")
def test_shrink_share(self):
share = self.create_share(size=2, cleanup_in_class=False)
new_size = 1
# shrink share and wait for active status
self.shares_client.shrink_share(share['id'], new_size)
self.shares_client.wait_for_share_status(share['id'], 'available')
# check state and new size
share = self.shares_client.get_share(share['id'])
self.assertEqual(new_size, share['size'])
class SharesRenameTest(base.BaseSharesTest):
@classmethod
def resource_setup(cls):
super(SharesRenameTest, cls).resource_setup()
# create share
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)
if CONF.share.run_snapshot_tests:
# create snapshot
cls.snap_name = data_utils.rand_name("tempest-snapshot-name")
cls.snap_desc = data_utils.rand_name(
"tempest-snapshot-description")
cls.snap = cls.create_snapshot_wait_for_active(
cls.share["id"], cls.snap_name, cls.snap_desc)
@test.attr(type=["gate", ])
def test_update_share(self):
# get share
share = self.shares_client.get_share(self.share['id'])
self.assertEqual(self.share_name, share["name"])
self.assertEqual(self.share_desc, share["description"])
self.assertFalse(share["is_public"])
# update share
new_name = data_utils.rand_name("tempest-new-name")
new_desc = data_utils.rand_name("tempest-new-description")
updated = self.shares_client.update_share(
share["id"], new_name, new_desc, is_public=True)
self.assertEqual(new_name, updated["name"])
self.assertEqual(new_desc, updated["description"])
self.assertTrue(updated["is_public"])
# get share
share = self.shares_client.get_share(self.share['id'])
self.assertEqual(new_name, share["name"])
self.assertEqual(new_desc, share["description"])
self.assertTrue(share["is_public"])
@test.attr(type=["gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_rename_snapshot(self):
# get snapshot
get = self.shares_client.get_snapshot(self.snap["id"])
self.assertEqual(self.snap_name, get["name"])
self.assertEqual(self.snap_desc, get["description"])
# rename snapshot
new_name = data_utils.rand_name("tempest-new-name-for-snapshot")
new_desc = data_utils.rand_name("tempest-new-description-for-snapshot")
renamed = self.shares_client.rename_snapshot(
self.snap["id"], new_name, new_desc)
self.assertEqual(new_name, renamed["name"])
self.assertEqual(new_desc, renamed["description"])
# get snapshot
get = self.shares_client.get_snapshot(self.snap["id"])
self.assertEqual(new_name, get["name"])
self.assertEqual(new_desc, get["description"])

View File

@ -0,0 +1,136 @@
# Copyright 2015 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests import clients_share as clients
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class SharesActionsNegativeTest(base.BaseSharesTest):
@classmethod
def resource_setup(cls):
super(SharesActionsNegativeTest, cls).resource_setup()
cls.share = cls.create_share(
size=1,
)
@test.attr(type=["negative", ])
@testtools.skipUnless(
CONF.share.run_extend_tests,
"Share extend tests are disabled.")
def test_share_extend_over_quota(self):
tenant_quotas = self.shares_client.show_quotas(
self.shares_client.tenant_id)
new_size = int(tenant_quotas["gigabytes"]) + 1
# extend share with over quota and check result
self.assertRaises(lib_exc.Forbidden,
self.shares_client.extend_share,
self.share['id'],
new_size)
@test.attr(type=["negative", ])
@testtools.skipUnless(
CONF.share.run_extend_tests,
"Share extend tests are disabled.")
def test_share_extend_with_less_size(self):
new_size = int(self.share['size']) - 1
# extend share with invalid size and check result
self.assertRaises(lib_exc.BadRequest,
self.shares_client.extend_share,
self.share['id'],
new_size)
@test.attr(type=["negative", ])
@testtools.skipUnless(
CONF.share.run_extend_tests,
"Share extend tests are disabled.")
def test_share_extend_with_same_size(self):
new_size = int(self.share['size'])
# extend share with invalid size and check result
self.assertRaises(lib_exc.BadRequest,
self.shares_client.extend_share,
self.share['id'],
new_size)
@test.attr(type=["negative", ])
@testtools.skipUnless(
CONF.share.run_extend_tests,
"Share extend tests are disabled.")
def test_share_extend_with_invalid_share_state(self):
share = self.create_share(size=1, cleanup_in_class=False)
new_size = int(share['size']) + 1
# set "error" state
admin_client = clients.AdminManager().shares_client
admin_client.reset_state(share['id'])
# run extend operation on same share and check result
self.assertRaises(lib_exc.BadRequest,
self.shares_client.extend_share,
share['id'],
new_size)
@test.attr(type=["negative", ])
@testtools.skipUnless(
CONF.share.run_shrink_tests,
"Share shrink tests are disabled.")
def test_share_shrink_with_greater_size(self):
new_size = int(self.share['size']) + 1
# shrink share with invalid size and check result
self.assertRaises(lib_exc.BadRequest,
self.shares_client.shrink_share,
self.share['id'],
new_size)
@test.attr(type=["negative", ])
@testtools.skipUnless(
CONF.share.run_shrink_tests,
"Share shrink tests are disabled.")
def test_share_shrink_with_same_size(self):
new_size = int(self.share['size'])
# shrink share with invalid size and check result
self.assertRaises(lib_exc.BadRequest,
self.shares_client.shrink_share,
self.share['id'],
new_size)
@test.attr(type=["negative", ])
@testtools.skipUnless(
CONF.share.run_shrink_tests,
"Share shrink tests are disabled.")
def test_share_shrink_with_invalid_share_state(self):
share = self.create_share(size=2, cleanup_in_class=False)
new_size = int(share['size']) - 1
# set "error" state
admin_client = clients.AdminManager().shares_client
admin_client.reset_state(share['id'])
# run shrink operation on same share and check result
self.assertRaises(lib_exc.BadRequest,
self.shares_client.shrink_share,
share['id'],
new_size)

View File

@ -0,0 +1,259 @@
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib import exceptions as lib_exc # noqa
import testtools # noqa
from manila_tempest_tests import share_exceptions
from manila_tempest_tests.tests.api import base
CONF = config.CONF
class SharesNegativeTest(base.BaseSharesTest):
@classmethod
def resource_setup(cls):
super(SharesNegativeTest, cls).resource_setup()
cls.share = cls.create_share(
name='public_share',
description='public_share_desc',
size=1,
is_public=True,
metadata={'key': 'value'}
)
@test.attr(type=["negative", "smoke", "gate", ])
def test_create_share_with_invalid_protocol(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_share,
share_protocol="nonexistent_protocol")
@test.attr(type=["negative", "smoke", "gate", ])
def test_create_share_with_wrong_public_value(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_share, is_public='truebar')
@test.attr(type=["negative", "smoke", "gate", ])
def test_update_share_with_wrong_public_value(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.update_share, self.share["id"],
is_public="truebar")
@test.attr(type=["negative", "smoke", "gate", ])
def test_get_share_with_wrong_id(self):
self.assertRaises(lib_exc.NotFound, self.shares_client.get_share,
"wrong_share_id")
@test.attr(type=["negative", "smoke", "gate", ])
def test_get_share_without_passing_share_id(self):
# Should not be able to get share when empty ID is passed
self.assertRaises(lib_exc.NotFound,
self.shares_client.get_share, '')
@test.attr(type=["negative", "smoke", "gate", ])
def test_list_shares_nonadmin_with_nonexistent_share_server_filter(self):
# filtering by share server allowed only for admins by default
self.assertRaises(lib_exc.Forbidden,
self.shares_client.list_shares_with_detail,
{'share_server_id': 'fake_share_server_id'})
@test.attr(type=["negative", "smoke", "gate", ])
def test_delete_share_with_wrong_id(self):
self.assertRaises(lib_exc.NotFound, self.shares_client.delete_share,
"wrong_share_id")
@test.attr(type=["negative", "smoke", "gate", ])
def test_delete_share_without_passing_share_id(self):
# Should not be able to delete share when empty ID is passed
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_share, '')
@test.attr(type=["negative", "smoke", "gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_create_snapshot_with_wrong_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.create_snapshot,
"wrong_share_id")
@test.attr(type=["negative", "smoke", "gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_delete_snapshot_with_wrong_id(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.delete_snapshot,
"wrong_share_id")
@test.attr(type=["negative", "smoke", "gate", ])
def test_create_share_with_invalid_size(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_share, size="#$%")
@test.attr(type=["negative", "smoke", "gate", ])
def test_create_share_with_out_passing_size(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_share, size="")
@test.attr(type=["negative", "smoke", "gate", ])
def test_create_share_with_zero_size(self):
self.assertRaises(lib_exc.BadRequest,
self.shares_client.create_share, size=0)
@test.attr(type=["negative", "gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_try_delete_share_with_existing_snapshot(self):
# share can not be deleted while snapshot exists
# create share
share = self.create_share()
# create snapshot
self.create_snapshot_wait_for_active(share["id"])
# try delete share
self.assertRaises(lib_exc.Forbidden,
self.shares_client.delete_share, share["id"])
@test.attr(type=["negative", "gate", ])
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_create_share_from_snap_with_less_size(self):
# requires minimum 5Gb available space
skip_msg = "Check disc space for this test"
try: # create share
share = self.create_share(size=2, cleanup_in_class=False)
except share_exceptions.ShareBuildErrorException:
self.skip(skip_msg)
try: # create snapshot
snap = self.create_snapshot_wait_for_active(
share["id"], cleanup_in_class=False)
except share_exceptions.SnapshotBuildErrorException:
self.skip(skip_msg)
# try create share from snapshot with less size
self.assertRaises(lib_exc.BadRequest,
self.create_share,
size=1, snapshot_id=snap["id"],
cleanup_in_class=False)
@test.attr(type=["negative", "smoke", "gate", ])
@testtools.skipIf(not CONF.share.multitenancy_enabled,
"Only for multitenancy.")
def test_create_share_with_nonexistant_share_network(self):
self.assertRaises(lib_exc.NotFound,
self.shares_client.create_share,
share_network_id="wrong_sn_id")
@test.attr(type=["negative", "smoke", "gate", ])
@testtools.skipIf(not CONF.share.multitenancy_enabled,
"Only for multitenancy.")
@testtools.skipUnless(CONF.share.run_snapshot_tests,
"Snapshot tests are disabled.")
def test_create_share_from_snap_with_different_share_network(self):
# create share
share = self.create_share(cleanup_in_class=False)
# get parent's share network
parent_share = self.shares_client.get_share(share["id"])
parent_sn = self.shares_client.get_share_network(
parent_share["share_network_id"])
# create new share-network - net duplicate of parent's share
new_duplicated_sn = self.create_share_network(
cleanup_in_class=False,
neutron_net_id=parent_sn["neutron_net_id"],
neutron_subnet_id=parent_sn["neutron_subnet_id"],
)
# create snapshot of parent share
snap = self.create_snapshot_wait_for_active(
share["id"], cleanup_in_class=False)
# try create share with snapshot using another share-network
# 400 bad request is expected
self.assertRaises(
lib_exc.BadRequest,
self.create_share,
cleanup_in_class=False,
share_network_id=new_duplicated_sn["id"],
snapshot_id=snap["id"],
)
@test.attr(type=["gate", "smoke", "negative", ])
def test_update_other_tenants_public_share(self):
isolated_client = self.get_client_with_isolated_creds(
type_of_creds='alt')
self.assertRaises(lib_exc.Forbidden, isolated_client.update_share,
self.share["id"], name="new_name")
@test.attr(type=["gate", "smoke", "negative", ])
def test_delete_other_tenants_public_share(self):
isolated_client = self.get_client_with_isolated_creds(
type_of_creds='alt')
self.assertRaises(lib_exc.Forbidden,
isolated_client.delete_share,
self.share['id'])
@test.attr(type=["gate", "smoke", "negative", ])
def test_set_metadata_of_other_tenants_public_share(self):
isolated_client = self.get_client_with_isolated_creds(
type_of_creds='alt')
self.assertRaises(lib_exc.Forbidden,
isolated_client.set_metadata,
self.share['id'],
{'key': 'value'})
@test.attr(type=["gate", "smoke", "negative", ])
def test_update_metadata_of_other_tenants_public_share(self):
isolated_client = self.get_client_with_isolated_creds(
type_of_creds='alt')
self.assertRaises(lib_exc.Forbidden,
isolated_client.update_all_metadata,
self.share['id'],
{'key': 'value'})
@test.attr(type=["gate", "smoke", "negative", ])
def test_delete_metadata_of_other_tenants_public_share(self):
isolated_client = self.get_client_with_isolated_creds(
type_of_creds='alt')
self.assertRaises(lib_exc.Forbidden,
isolated_client.delete_metadata,
self.share['id'],
'key')
@test.attr(type=["gate", "smoke", "negative", ])
def test_list_by_share_server_by_user(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.list_shares,
params={'share_server_id': 12345})
@test.attr(type=["gate", "smoke", "negative", ])
def test_manage_share_by_user(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.manage_share,
'fake-host', 'nfs', '/export/path',
'fake-type')
@test.attr(type=["gate", "smoke", "negative", ])
def test_unmanage_share_by_user(self):
self.assertRaises(lib_exc.Forbidden,
self.shares_client.unmanage_share,
'fake-id')

View File

@ -0,0 +1,184 @@
# Copyright 2015 Deutsche Telekom AG
# 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 oslo_log import log
import six
from tempest.common.utils.linux import remote_client # noqa
from tempest import config # noqa
from tempest.scenario import manager # noqa
from tempest_lib.common.utils import data_utils
from manila_tempest_tests import clients_share
CONF = config.CONF
LOG = log.getLogger(__name__)
class ShareScenarioTest(manager.NetworkScenarioTest):
"""Provide harness to do Manila scenario tests."""
@classmethod
def resource_setup(cls):
cls.set_network_resources()
super(ShareScenarioTest, cls).resource_setup()
# Manila clients
cls.shares_client = clients_share.Manager().shares_client
cls.shares_admin_client = clients_share.AdminManager().shares_client
def _create_share(self, share_protocol=None, size=1, name=None,
snapshot_id=None, description=None, metadata=None,
share_network_id=None, share_type_id=None,
client=None, cleanup_in_class=True):
"""Create a share
:param share_protocol: NFS or CIFS
:param size: size in GB
:param name: name of the share (otherwise random)
:param snapshot_id: snapshot as basis for the share
:param description: description of the share
:param metadata: adds additional metadata
:param share_network_id: id of network to be used
:param share_type_id: type of the share to be created
:param client: client object
:param cleanup_in_class: default: True
:returns: a created share
"""
client = client or self.shares_client
description = description or "Tempest's share"
if not name:
name = data_utils.rand_name("manila-scenario")
share_network_id = share_network_id or client.share_network_id or None
metadata = metadata or {}
kwargs = {
'share_protocol': share_protocol,
'size': size,
'name': name,
'snapshot_id': snapshot_id,
'description': description,
'metadata': metadata,
'share_network_id': share_network_id,
'share_type_id': share_type_id,
}
share = self.shares_client.create_share(**kwargs)
self.addCleanup(client.wait_for_resource_deletion,
share_id=share['id'])
self.addCleanup(client.delete_share,
share['id'])
client.wait_for_share_status(share['id'], 'available')
return share
def _wait_for_share_server_deletion(self, sn_id, client=None):
"""Wait for a share server to be deleted
:param sn_id: shared network id
:param client: client object
"""
client = client or self.shares_admin_client
servers = client.list_share_servers(
search_opts={"share_network": sn_id})
for server in servers:
client.delete_share_server(server['id'])
client.wait_for_resource_deletion(server_id=server['id'])
def _create_share_network(self, client=None, **kwargs):
"""Create a share network
:param client: client object
:returns: a created share network
"""
client = client or self.shares_client
sn = client.create_share_network(**kwargs)
self.addCleanup(client.wait_for_resource_deletion,
sn_id=sn['id'])
self.addCleanup(client.delete_share_network,
sn['id'])
self.addCleanup(self._wait_for_share_server_deletion,
sn['id'])
return sn
def _allow_access(self, share_id, client=None,
access_type="ip", access_to="0.0.0.0"):
"""Allow share access
:param share_id: id of the share
:param client: client object
:param access_type: "ip", "user" or "cert"
:param access_to
:returns: access object
"""
client = client or self.shares_client
access = client.create_access_rule(share_id, access_type, access_to)
client.wait_for_access_rule_status(share_id, access['id'], "active")
self.addCleanup(client.delete_access_rule,
share_id, access['id'])
return access
def _create_router_interface(self, subnet_id, client=None,
tenant_id=None, router_id=None):
"""Create a router interface
:param subnet_id: id of the subnet
:param client: client object
:param tenant_id
"""
if not client:
client = self.network_client
if not tenant_id:
tenant_id = client.tenant_id
if not router_id:
router_id = self._get_router()['id']
client.add_router_interface_with_subnet_id(router_id,
subnet_id)
self.addCleanup(client.remove_router_interface_with_subnet_id,
router_id, subnet_id)
def get_remote_client(self, *args, **kwargs):
if not CONF.share.image_with_share_tools:
return super(ShareScenarioTest,
self).get_remote_client(*args, **kwargs)
# NOTE(u_glide): We need custom implementation of this method until
# original implementation depends on CONF.compute.ssh_auth_method
# option.
server_or_ip = kwargs['server_or_ip']
if isinstance(server_or_ip, six.string_types):
ip = server_or_ip
else:
addr = server_or_ip['addresses'][CONF.compute.network_for_ssh][0]
ip = addr['addr']
# NOTE(u_glide): Both options (pkey and password) are required here to
# support service images without Nova metadata support
client_params = {
'username': kwargs['username'],
'password': CONF.share.image_password,
'pkey': kwargs.get('private_key'),
}
linux_client = remote_client.RemoteClient(ip, **client_params)
try:
linux_client.validate_authentication()
except Exception:
LOG.exception('Initializing SSH connection to %s failed' % ip)
self._log_console_output()
raise
return linux_client

View File

@ -0,0 +1,218 @@
# Copyright 2015 Deutsche Telekom AG
# 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 oslo_log import log as logging
from tempest import config # noqa
from tempest import test # noqa
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions
from manila_tempest_tests.tests.scenario import manager_share as manager
CONF = config.CONF
LOG = logging.getLogger(__name__)
class ShareBasicOpsBase(manager.ShareScenarioTest):
"""This smoke test case follows this basic set of operations:
* Create share network
* Create share
* Launch an instance
* Allow access
* Perform ssh to instance
* Mount share
* Terminate the instance
"""
protocol = None
def setUp(self):
super(ShareBasicOpsBase, self).setUp()
# Setup image and flavor the test instance
# Support both configured and injected values
if not hasattr(self, 'flavor_ref'):
self.flavor_ref = CONF.share.client_vm_flavor_ref
if CONF.share.image_with_share_tools:
images = self.images_client.list_images()["images"]
for img in images:
if img["name"] == CONF.share.image_with_share_tools:
self.image_ref = img['id']
break
if not self.image_ref:
msg = ("Image %s not found" %
CONF.share.image_with_share_tools)
raise exceptions.InvalidConfiguration(message=msg)
self.ssh_user = CONF.share.image_username
LOG.debug('Starting test for i:{image}, f:{flavor}. '
'user: {ssh_user}'.format(
image=self.image_ref, flavor=self.flavor_ref,
ssh_user=self.ssh_user))
def boot_instance(self, network):
self.keypair = self.create_keypair()
security_groups = [{'name': self.security_group['name']}]
create_kwargs = {
'networks': [
{'uuid': network['id']},
],
'key_name': self.keypair['name'],
'security_groups': security_groups,
}
instance = self.create_server(image=self.image_ref,
create_kwargs=create_kwargs,
flavor=self.flavor_ref)
return instance
def init_ssh(self, instance, do_ping=False):
# Obtain a floating IP
floating_ip = (self.floating_ips_client.create_floating_ip()
['floating_ip'])
self.addCleanup(self.delete_wrapper,
self.floating_ips_client.delete_floating_ip,
floating_ip['id'])
# Attach a floating IP
self.floating_ips_client.associate_floating_ip_to_server(
floating_ip['ip'], instance['id'])
# Check ssh
ssh_client = self.get_remote_client(
server_or_ip=floating_ip['ip'],
username=self.ssh_user,
private_key=self.keypair['private_key'])
# NOTE(u_glide): Workaround for bug #1465682
ssh_client = ssh_client.ssh_client
self.share = self.shares_client.get_share(self.share['id'])
if do_ping:
server_ip = self.share['export_location'].split(":")[0]
ssh_client.exec_command("ping -c 1 %s" % server_ip)
return ssh_client
def mount_share(self, location, ssh_client):
raise NotImplementedError
def umount_share(self, ssh_client):
ssh_client.exec_command("sudo umount /mnt")
def write_data(self, data, ssh_client):
ssh_client.exec_command("echo \"%s\" | sudo tee /mnt/t1 && sudo sync" %
data)
def read_data(self, ssh_client):
data = ssh_client.exec_command("sudo cat /mnt/t1")
return data.rstrip()
def create_share_network(self):
self.net = self._create_network(namestart="manila-share")
self.subnet = self._create_subnet(network=self.net,
namestart="manila-share-sub")
router = self._get_router()
self._create_router_interface(subnet_id=self.subnet['id'],
router_id=router['id'])
self.share_net = self._create_share_network(
neutron_net_id=self.net['id'],
neutron_subnet_id=self.subnet['id'],
name=data_utils.rand_name("sn-name"))
def create_share(self, share_net_id):
self.share = self._create_share(share_protocol=self.protocol,
share_network_id=share_net_id)
def allow_access_ip(self, share_id, ip=None, instance=None):
if instance and not ip:
try:
net_addresses = instance['addresses']
first_address = net_addresses.values()[0][0]
ip = first_address['addr']
except Exception:
# In case on an error ip will be still none
LOG.exception("Instance does not have a valid IP address."
"Falling back to default")
if not ip:
ip = '0.0.0.0/0'
self._allow_access(share_id, access_type='ip', access_to=ip)
@test.services('compute', 'network')
def test_mount_share_one_vm(self):
self.security_group = self._create_security_group()
self.create_share_network()
self.create_share(self.share_net['id'])
instance = self.boot_instance(self.net)
self.allow_access_ip(self.share['id'], instance=instance)
ssh_client = self.init_ssh(instance)
for location in self.share['export_locations']:
self.mount_share(location, ssh_client)
self.umount_share(ssh_client)
self.servers_client.delete_server(instance['id'])
@test.services('compute', 'network')
def test_read_write_two_vms(self):
"""Boots two vms and writes/reads data on it."""
test_data = "Some test data to write"
self.security_group = self._create_security_group()
self.create_share_network()
self.create_share(self.share_net['id'])
# boot first VM and write data
instance1 = self.boot_instance(self.net)
self.allow_access_ip(self.share['id'], instance=instance1)
ssh_client_inst1 = self.init_ssh(instance1)
first_location = self.share['export_locations'][0]
self.mount_share(first_location, ssh_client_inst1)
self.addCleanup(self.umount_share,
ssh_client_inst1)
self.write_data(test_data, ssh_client_inst1)
# boot second VM and read
instance2 = self.boot_instance(self.net)
self.allow_access_ip(self.share['id'], instance=instance2)
ssh_client_inst2 = self.init_ssh(instance2)
self.mount_share(first_location, ssh_client_inst2)
self.addCleanup(self.umount_share,
ssh_client_inst2)
data = self.read_data(ssh_client_inst2)
self.assertEqual(test_data, data)
class TestShareBasicOpsNFS(ShareBasicOpsBase):
protocol = "NFS"
def mount_share(self, location, ssh_client):
ssh_client.exec_command("sudo mount \"%s\" /mnt" % location)
class TestShareBasicOpsCIFS(ShareBasicOpsBase):
protocol = "CIFS"
def mount_share(self, location, ssh_client):
location = location.replace("\\", "/")
ssh_client.exec_command(
"sudo mount.cifs \"%s\" /mnt -o guest" % location
)
# NOTE(u_glide): this function is required to exclude ShareBasicOpsBase from
# executed test cases.
# See: https://docs.python.org/2/library/unittest.html#load-tests-protocol
# for details.
def load_tests(loader, tests, _):
result = []
for test_case in tests:
if type(test_case._tests[0]) is ShareBasicOpsBase:
continue
result.append(test_case)
return loader.suiteClass(result)