Merge "Add unit test for volume extensions client"
diff --git a/doc/source/library.rst b/doc/source/library.rst
index 29248d1..a461a0f 100644
--- a/doc/source/library.rst
+++ b/doc/source/library.rst
@@ -68,3 +68,4 @@
library/api_microversion_testing
library/auth
library/clients
+ library/credential_providers
diff --git a/doc/source/library/credential_providers.rst b/doc/source/library/credential_providers.rst
new file mode 100644
index 0000000..7e831cc
--- /dev/null
+++ b/doc/source/library/credential_providers.rst
@@ -0,0 +1,148 @@
+.. _cred_providers:
+
+Credential Providers
+====================
+
+These library interfaces are used to deal with allocating credentials on demand
+either dynamically by calling keystone to allocate new credentials, or from
+a list of preprovisioned credentials. These 2 modules are implementations of
+the same abstract credential providers class and can be used interchangably.
+However, each implementation has some additional parameters that are used to
+influence the behavior of the modules. The API reference at the bottom of this
+doc shows the interface definitions for both modules, however that may be a bit
+opaque. You can see some examples of how to leverage this interface below.
+
+Initialization Example
+----------------------
+This example is from Tempest itself (from tempest/common/credentials_factory.py
+just modified slightly) and is how it initializes the credential provider based
+on config::
+
+ from tempest import config
+ from tempest.lib.common import dynamic_creds
+ from tempest.lib.common import preprov_creds
+
+ CONF = config.CONF
+
+ def get_credentials_provider(name, network_resources=None,
+ force_tenant_isolation=False,
+ identity_version=None):
+ # If a test requires a new account to work, it can have it via forcing
+ # dynamic credentials. A new account will be produced only for that test.
+ # In case admin credentials are not available for the account creation,
+ # the test should be skipped else it would fail.
+ identity_version = identity_version or CONF.identity.auth_version
+ if CONF.auth.use_dynamic_credentials or force_tenant_isolation:
+ admin_creds = get_configured_admin_credentials(
+ fill_in=True, identity_version=identity_version)
+ return dynamic_creds.DynamicCredentialProvider(
+ name=name,
+ network_resources=network_resources,
+ identity_version=identity_version,
+ admin_creds=admin_creds,
+ identity_admin_domain_scope=CONF.identity.admin_domain_scope,
+ identity_admin_role=CONF.identity.admin_role,
+ extra_roles=CONF.auth.tempest_roles,
+ neutron_available=CONF.service_available.neutron,
+ project_network_cidr=CONF.network.project_network_cidr,
+ project_network_mask_bits=CONF.network.project_network_mask_bits,
+ public_network_id=CONF.network.public_network_id,
+ create_networks=(CONF.auth.create_isolated_networks and not
+ CONF.network.shared_physical_network),
+ resource_prefix=CONF.resources_prefix,
+ credentials_domain=CONF.auth.default_credentials_domain_name,
+ admin_role=CONF.identity.admin_role,
+ identity_uri=CONF.identity.uri_v3,
+ identity_admin_endpoint_type=CONF.identity.v3_endpoint_type)
+ else:
+ if CONF.auth.test_accounts_file:
+ # Most params are not relevant for pre-created accounts
+ return preprov_creds.PreProvisionedCredentialProvider(
+ name=name, identity_version=identity_version,
+ accounts_lock_dir=lockutils.get_lock_path(CONF),
+ test_accounts_file=CONF.auth.test_accounts_file,
+ object_storage_operator_role=CONF.object_storage.operator_role,
+ object_storage_reseller_admin_role=reseller_admin_role,
+ credentials_domain=CONF.auth.default_credentials_domain_name,
+ admin_role=CONF.identity.admin_role,
+ identity_uri=CONF.identity.uri_v3,
+ identity_admin_endpoint_type=CONF.identity.v3_endpoint_type)
+ else:
+ raise exceptions.InvalidConfiguration(
+ 'A valid credential provider is needed')
+
+This function just returns an initialized credential provider class based on the
+config file. The consumer of this function treats the output as the same
+regardless of whether it's a dynamic or preprovisioned provider object.
+
+Dealing with Credentials
+------------------------
+
+Once you have a credential provider object created the access patterns for
+allocating and removing credentials are the same across both the dynamic
+and preprovisioned credentials. These are defined in the abstract
+CredentialProvider class. At a high level the credentials provider enables
+you to get 3 basic types of credentials at once (per object): a primary, alt,
+and admin. You're also able to allocate a credential by role. These credentials
+are tracked by the provider object and delete must manually be called otherwise
+the created resources will not be deleted (or returned to the pool in the case
+of preprovisioned creds)
+
+Examples
+''''''''
+
+Continuing from the example above, to allocate credentials by the 3 basic types
+you can do the following::
+
+ provider = get_credentials_provider('my_tests')
+ primary_creds = provider.get_primary_creds()
+ alt_creds = provider.get_alt_creds()
+ admin_creds = provider.get_admin_creds()
+ # Make sure to delete the credentials when you're finished
+ provider.clear_creds()
+
+To create and interact with credentials by role you can do the following::
+
+ provider = get_credentials_provider('my_tests')
+ my_role_creds = provider.get_creds_by_role({'roles': ['my_role']})
+ # provider.clear_creds() will clear all creds including those allocated by
+ # role
+ provider.clear_creds()
+
+When multiple roles are specified a set of creds with all the roles assigned
+will be allocated::
+
+ provider = get_credentials_provider('my_tests')
+ my_role_creds = provider.get_creds_by_role({'roles': ['my_role',
+ 'my_other_role']})
+ # provider.clear_creds() will clear all creds including those allocated by
+ # role
+ provider.clear_creds()
+
+If you need multiple sets of credentials with the same roles you can also do
+this by leveraging the ``force_new`` kwarg::
+
+ provider = get_credentials_provider('my_tests')
+ my_role_creds = provider.get_creds_by_role({'roles': ['my_role']})
+ my_role_other_creds = provider.get_creds_by_role({'roles': ['my_role']},
+ force_new=True)
+ # provider.clear_creds() will clear all creds including those allocated by
+ # role
+ provider.clear_creds()
+
+API Reference
+=============
+
+------------------------------
+The dynamic credentials module
+------------------------------
+
+.. automodule:: tempest.lib.common.dynamic_creds
+ :members:
+
+--------------------------------------
+The pre-provisioned credentials module
+--------------------------------------
+
+.. automodule:: tempest.lib.common.preprov_creds
+ :members:
diff --git a/releasenotes/notes/migrate-dynamic-creds-ecebb47528080761.yaml b/releasenotes/notes/migrate-dynamic-creds-ecebb47528080761.yaml
new file mode 100644
index 0000000..c20cbc6
--- /dev/null
+++ b/releasenotes/notes/migrate-dynamic-creds-ecebb47528080761.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ The tempest module tempest.common.dynamic creds which is used for
+ dynamically allocating credentials has been migrated into tempest lib.
diff --git a/releasenotes/notes/migrate-preprov-creds-ef61a046ee1ec604.yaml b/releasenotes/notes/migrate-preprov-creds-ef61a046ee1ec604.yaml
new file mode 100644
index 0000000..aa5f71a
--- /dev/null
+++ b/releasenotes/notes/migrate-preprov-creds-ef61a046ee1ec604.yaml
@@ -0,0 +1,11 @@
+---
+features:
+ - The tempest module tempest.common.preprov_creds which is used to provide
+ credentials from a list of preprovisioned resources has been migrated into
+ tempest lib at tempest.lib.common.preprov_creds.
+ - The InvalidTestResource exception class from tempest.exceptions has been
+ migrated into tempest.lib.exceptions
+ - The tempest module tempest.common.fixed_network which provided utilities for
+ finding fixed networks by and helpers for picking the network to use when
+ multiple tenant networks are available has been migrated into tempest lib
+ at tempest.lib.common.fixed_network.
diff --git a/requirements.txt b/requirements.txt
index b7ebf8a..a74f5c2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,7 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
pbr!=2.1.0,>=2.0.0 # Apache-2.0
-cliff>=2.6.0 # Apache-2.0
+cliff>=2.8.0 # Apache-2.0
jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
testtools>=1.4.0 # MIT
paramiko>=2.0 # LGPLv2.1+
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 0521cca..d9a7800 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -14,8 +14,8 @@
from tempest.api.compute import base
from tempest.common import compute
-from tempest.common import fixed_network
from tempest.common import waiters
+from tempest.lib.common import fixed_network
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 921b7da..a4ed8e1 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -15,9 +15,9 @@
import testtools
from tempest.api.compute import base
-from tempest.common import fixed_network
from tempest.common import waiters
from tempest import config
+from tempest.lib.common import fixed_network
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 13614cb..11273e4 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -98,7 +98,7 @@
cls.policies = None
if CONF.object_storage_feature_enabled.discoverability:
- _, body = cls.capabilities_client.list_capabilities()
+ body = cls.capabilities_client.list_capabilities()
if 'swift' in body and 'policies' in body['swift']:
cls.policies = body['swift']['policies']
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index e765414..7c538e8 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -58,9 +58,9 @@
# upload an archived file
with open(filepath) as fh:
mydata = fh.read()
- resp, body = self.bulk_client.upload_archive(
+ resp = self.bulk_client.upload_archive(
upload_path='', data=mydata, archive_file_format='tar')
- return resp, body
+ return resp
def _check_contents_deleted(self, container_name):
param = {'format': 'txt'}
@@ -73,21 +73,20 @@
def test_extract_archive(self):
# Test bulk operation of file upload with an archived file
filepath, container_name, object_name = self._create_archive()
- resp, _ = self._upload_archive(filepath)
-
+ resp = self._upload_archive(filepath)
self.containers.append(container_name)
# When uploading an archived file with the bulk operation, the response
# does not contain 'content-length' header. This is the special case,
# therefore the existence of response headers is checked without
# custom matcher.
- self.assertIn('transfer-encoding', resp)
- self.assertIn('content-type', resp)
- self.assertIn('x-trans-id', resp)
- self.assertIn('date', resp)
+ self.assertIn('transfer-encoding', resp.response)
+ self.assertIn('content-type', resp.response)
+ self.assertIn('x-trans-id', resp.response)
+ self.assertIn('date', resp.response)
# Check only the format of common headers with custom matcher
- self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+ self.assertThat(resp.response, custom_matchers.AreAllWellFormatted())
param = {'format': 'json'}
resp, body = self.account_client.list_account_containers(param)
@@ -112,19 +111,19 @@
self._upload_archive(filepath)
data = '%s/%s\n%s' % (container_name, object_name, container_name)
- resp, _ = self.bulk_client.delete_bulk_data(data=data)
+ resp = self.bulk_client.delete_bulk_data(data=data)
# When deleting multiple files using the bulk operation, the response
# does not contain 'content-length' header. This is the special case,
# therefore the existence of response headers is checked without
# custom matcher.
- self.assertIn('transfer-encoding', resp)
- self.assertIn('content-type', resp)
- self.assertIn('x-trans-id', resp)
- self.assertIn('date', resp)
+ self.assertIn('transfer-encoding', resp.response)
+ self.assertIn('content-type', resp.response)
+ self.assertIn('x-trans-id', resp.response)
+ self.assertIn('date', resp.response)
# Check only the format of common headers with custom matcher
- self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+ self.assertThat(resp.response, custom_matchers.AreAllWellFormatted())
# Check if uploaded contents are completely deleted
self._check_contents_deleted(container_name)
@@ -138,19 +137,19 @@
data = '%s/%s\n%s' % (container_name, object_name, container_name)
- resp, _ = self.bulk_client.delete_bulk_data_with_post(data=data)
+ resp = self.bulk_client.delete_bulk_data_with_post(data=data)
# When deleting multiple files using the bulk operation, the response
# does not contain 'content-length' header. This is the special case,
# therefore the existence of response headers is checked without
# custom matcher.
- self.assertIn('transfer-encoding', resp)
- self.assertIn('content-type', resp)
- self.assertIn('x-trans-id', resp)
- self.assertIn('date', resp)
+ self.assertIn('transfer-encoding', resp.response)
+ self.assertIn('content-type', resp.response)
+ self.assertIn('x-trans-id', resp.response)
+ self.assertIn('date', resp.response)
# Check only the format of common headers with custom matcher
- self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+ self.assertThat(resp.response, custom_matchers.AreAllWellFormatted())
# Check if uploaded contents are completely deleted
self._check_contents_deleted(container_name)
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 9e62046..2fb676f 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -135,7 +135,7 @@
not CONF.object_storage_feature_enabled.discoverability,
'Discoverability function is disabled')
def test_list_extensions(self):
- resp, _ = self.capabilities_client.list_capabilities()
+ resp = self.capabilities_client.list_capabilities()
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
diff --git a/tempest/api/object_storage/test_container_services_negative.py b/tempest/api/object_storage/test_container_services_negative.py
index a8d70c5..387b7b6 100644
--- a/tempest/api/object_storage/test_container_services_negative.py
+++ b/tempest/api/object_storage/test_container_services_negative.py
@@ -32,7 +32,7 @@
if CONF.object_storage_feature_enabled.discoverability:
# use /info to get default constraints
- _, body = cls.capabilities_client.list_capabilities()
+ body = cls.capabilities_client.list_capabilities()
cls.constraints = body['swift']
@decorators.attr(type=["negative"])
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index a76123c..8636405 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -102,8 +102,8 @@
import yaml
from tempest.common import credentials_factory
-from tempest.common import dynamic_creds
from tempest import config
+from tempest.lib.common import dynamic_creds
LOG = None
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 2f4d120..8e71ecc 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -200,7 +200,7 @@
if service != 'swift':
resp = extensions_client.list_extensions()
else:
- __, resp = extensions_client.list_capabilities()
+ resp = extensions_client.list_capabilities()
# For Nova, Cinder and Neutron we use the alias name rather than the
# 'name' field because the alias is considered to be the canonical
# name.
diff --git a/tempest/common/compute.py b/tempest/common/compute.py
index 9f467fe..e3fbfb8 100644
--- a/tempest/common/compute.py
+++ b/tempest/common/compute.py
@@ -25,9 +25,9 @@
from oslo_log import log as logging
from oslo_utils import excutils
-from tempest.common import fixed_network
from tempest.common import waiters
from tempest import config
+from tempest.lib.common import fixed_network
from tempest.lib.common import rest_client
from tempest.lib.common.utils import data_utils
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
index 449c343..fd875be 100644
--- a/tempest/common/credentials_factory.py
+++ b/tempest/common/credentials_factory.py
@@ -14,10 +14,10 @@
from oslo_concurrency import lockutils
from tempest import clients
-from tempest.common import dynamic_creds
-from tempest.common import preprov_creds
from tempest import config
from tempest.lib import auth
+from tempest.lib.common import dynamic_creds
+from tempest.lib.common import preprov_creds
from tempest.lib import exceptions
CONF = config.CONF
@@ -147,12 +147,16 @@
'A valid credential provider is needed')
-# We want a helper function here to check and see if admin credentials
-# are available so we can do a single call from skip_checks if admin
-# creds area available.
-# This depends on identity_version as there may be admin credentials
-# available for v2 but not for v3.
def is_admin_available(identity_version):
+ """Helper to check for admin credentials
+
+ Helper function to check if a set of admin credentials is available so we
+ can do a single call from skip_checks.
+ This helper depends on identity_version as there may be admin credentials
+ available for v2 but not for v3.
+
+ :param identity_version: 'v2' or 'v3'
+ """
is_admin = True
# If dynamic credentials is enabled admin will be available
if CONF.auth.use_dynamic_credentials:
@@ -173,12 +177,16 @@
return is_admin
-# We want a helper function here to check and see if alt credentials
-# are available so we can do a single call from skip_checks if alt
-# creds area available.
-# This depends on identity_version as there may be alt credentials
-# available for v2 but not for v3.
def is_alt_available(identity_version):
+ """Helper to check for alt credentials
+
+ Helper function to check if a second set of credentials is available (aka
+ alt credentials) so we can do a single call from skip_checks.
+ This helper depends on identity_version as there may be alt credentials
+ available for v2 but not for v3.
+
+ :param identity_version: 'v2' or 'v3'
+ """
# If dynamic credentials is enabled alt will be available
if CONF.auth.use_dynamic_credentials:
return True
@@ -216,9 +224,19 @@
}
-# Read credentials from configuration, builds a Credentials object
-# based on the specified or configured version
def get_configured_admin_credentials(fill_in=True, identity_version=None):
+ """Get admin credentials from the config file
+
+ Read credentials from configuration, builds a Credentials object based on
+ the specified or configured version
+
+ :param fill_in: If True, a request to the Token API is submitted, and the
+ credential object is filled in with all names and IDs from
+ the token API response.
+ :param identity_version: The identity version to talk to and the type of
+ credentials object to be created. 'v2' or 'v3'.
+ :returns: An object of a sub-type of `auth.Credentials`
+ """
identity_version = identity_version or CONF.identity.auth_version
if identity_version not in ('v2', 'v3'):
@@ -250,6 +268,19 @@
# Wrapper around auth.get_credentials to use the configured identity version
# if none is specified
def get_credentials(fill_in=True, identity_version=None, **kwargs):
+ """Get credentials from dict based on config
+
+ Wrapper around auth.get_credentials to use the configured identity version
+ if none is specified.
+
+ :param fill_in: If True, a request to the Token API is submitted, and the
+ credential object is filled in with all names and IDs from
+ the token API response.
+ :param identity_version: The identity version to talk to and the type of
+ credentials object to be created. 'v2' or 'v3'.
+ :param kwargs: Attributes to be used to build the Credentials object.
+ :returns: An object of a sub-type of `auth.Credentials`
+ """
params = dict(DEFAULT_PARAMS, **kwargs)
identity_version = identity_version or CONF.identity.auth_version
# In case of "v3" add the domain from config if not specified
diff --git a/tempest/common/utils/__init__.py b/tempest/common/utils/__init__.py
index 84e31d0..e69de29 100644
--- a/tempest/common/utils/__init__.py
+++ b/tempest/common/utils/__init__.py
@@ -1,38 +0,0 @@
-# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
-#
-# 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 functools import partial
-
-from tempest import config
-from tempest.lib.common.utils import data_utils as lib_data_utils
-
-CONF = config.CONF
-
-
-class DataUtils(object):
- def __getattr__(self, attr):
-
- if attr == 'rand_name':
- # NOTE(flwang): This is a proxy to generate a random name that
- # includes a random number and a prefix if one is configured in
- # CONF.resources_prefix
- attr_obj = partial(lib_data_utils.rand_name,
- prefix=CONF.resources_prefix)
- else:
- attr_obj = getattr(lib_data_utils, attr)
-
- self.__dict__[attr] = attr_obj
- return attr_obj
-
-data_utils = DataUtils()
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index a437761..b5b2d71 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -52,12 +52,5 @@
"the configured network")
-# NOTE(andreaf) This exception is added here to facilitate the migration
-# of get_network_from_name and preprov_creds to tempest.lib, and it should
-# be migrated along with them
-class InvalidTestResource(exceptions.TempestException):
- message = "%(name)s is not a valid %(type)s, or the name is ambiguous"
-
-
class RFCViolation(exceptions.RestClientException):
message = "RFC Violation"
diff --git a/tempest/common/dynamic_creds.py b/tempest/lib/common/dynamic_creds.py
similarity index 100%
rename from tempest/common/dynamic_creds.py
rename to tempest/lib/common/dynamic_creds.py
diff --git a/tempest/common/fixed_network.py b/tempest/lib/common/fixed_network.py
similarity index 99%
rename from tempest/common/fixed_network.py
rename to tempest/lib/common/fixed_network.py
index 4032c90..e2054a4 100644
--- a/tempest/common/fixed_network.py
+++ b/tempest/lib/common/fixed_network.py
@@ -14,8 +14,8 @@
from oslo_log import log as logging
-from tempest import exceptions
from tempest.lib.common.utils import test_utils
+from tempest.lib import exceptions
LOG = logging.getLogger(__name__)
diff --git a/tempest/common/preprov_creds.py b/tempest/lib/common/preprov_creds.py
similarity index 98%
rename from tempest/common/preprov_creds.py
rename to tempest/lib/common/preprov_creds.py
index 64cabb7..cd3a10e 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/lib/common/preprov_creds.py
@@ -20,10 +20,9 @@
import six
import yaml
-from tempest.common import fixed_network
-from tempest import exceptions
from tempest.lib import auth
from tempest.lib.common import cred_provider
+from tempest.lib.common import fixed_network
from tempest.lib import exceptions as lib_exc
from tempest.lib.services import clients
@@ -350,7 +349,7 @@
try:
network = fixed_network.get_network_from_name(
net_name, compute_network_client)
- except exceptions.InvalidTestResource:
+ except lib_exc.InvalidTestResource:
network = {}
net_creds.set_resources(network=network)
return net_creds
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index 68ce57a..cdb8be9 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -269,3 +269,7 @@
class DeleteErrorException(TempestException):
message = ("Resource %(resource_id)s failed to delete "
"and is in ERROR status")
+
+
+class InvalidTestResource(TempestException):
+ message = "%(name)s is not a valid %(type)s, or the name is ambiguous"
diff --git a/tempest/services/object_storage/bulk_middleware_client.py b/tempest/services/object_storage/bulk_middleware_client.py
index 83d2d80..c11a105 100644
--- a/tempest/services/object_storage/bulk_middleware_client.py
+++ b/tempest/services/object_storage/bulk_middleware_client.py
@@ -31,7 +31,7 @@
headers = {}
resp, body = self.put(url, data, headers)
self.expected_success(200, resp.status)
- return resp, body
+ return rest_client.ResponseBodyData(resp, body)
def delete_bulk_data(self, data=None, headers=None):
"""Delete multiple objects or containers from their account.
@@ -43,9 +43,9 @@
if headers is None:
headers = {}
- resp, body = self.delete(url, headers=headers, body=data)
+ resp, body = self.delete(url, headers, data)
self.expected_success(200, resp.status)
- return resp, body
+ return rest_client.ResponseBodyData(resp, body)
def delete_bulk_data_with_post(self, data=None, headers=None):
"""Delete multiple objects or containers with POST request.
@@ -57,6 +57,6 @@
if headers is None:
headers = {}
- resp, body = self.post(url, headers=headers, body=data)
+ resp, body = self.post(url, data, headers)
self.expected_success([200, 204], resp.status)
- return resp, body
+ return rest_client.ResponseBodyData(resp, body)
diff --git a/tempest/services/object_storage/capabilities_client.py b/tempest/services/object_storage/capabilities_client.py
index 0fe437f..d31bbc2 100644
--- a/tempest/services/object_storage/capabilities_client.py
+++ b/tempest/services/object_storage/capabilities_client.py
@@ -28,4 +28,4 @@
self.reset_path()
body = json.loads(body)
self.expected_success(200, resp.status)
- return resp, body
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/test.py b/tempest/test.py
index fc846ff..317c0a7 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -26,10 +26,10 @@
from tempest import clients
from tempest.common import credentials_factory as credentials
-from tempest.common import fixed_network
import tempest.common.validation_resources as vresources
from tempest import config
from tempest.lib.common import cred_client
+from tempest.lib.common import fixed_network
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
diff --git a/tempest/tests/cmd/test_account_generator.py b/tempest/tests/cmd/test_account_generator.py
index 248cfb0..f907bd0 100644
--- a/tempest/tests/cmd/test_account_generator.py
+++ b/tempest/tests/cmd/test_account_generator.py
@@ -140,7 +140,8 @@
identity_version = 2
cred_client = 'tempest.lib.common.cred_client.V2CredsClient'
- dynamic_creds = 'tempest.common.dynamic_creds.DynamicCredentialProvider'
+ dynamic_creds = ('tempest.lib.common.dynamic_creds.'
+ 'DynamicCredentialProvider')
def setUp(self):
super(TestGenerateResourcesV2, self).setUp()
@@ -245,7 +246,8 @@
identity_version = 2
cred_client = 'tempest.lib.common.cred_client.V2CredsClient'
- dynamic_creds = 'tempest.common.dynamic_creds.DynamicCredentialProvider'
+ dynamic_creds = ('tempest.lib.common.dynamic_creds.'
+ 'DynamicCredentialProvider')
domain_is_in = False
def setUp(self):
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index b0e74fb..1415111 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -392,10 +392,10 @@
def test_verify_extensions_swift(self):
def fake_list_extensions():
- return (None, {'fake1': 'metadata',
- 'fake2': 'metadata',
- 'not_fake': 'metadata',
- 'swift': 'metadata'})
+ return {'fake1': 'metadata',
+ 'fake2': 'metadata',
+ 'not_fake': 'metadata',
+ 'swift': 'metadata'}
fake_os = mock.MagicMock()
fake_os.capabilities_client.list_capabilities = fake_list_extensions
self.useFixture(fixtures.MockPatchObject(
@@ -414,10 +414,10 @@
def test_verify_extensions_swift_all(self):
def fake_list_extensions():
- return (None, {'fake1': 'metadata',
- 'fake2': 'metadata',
- 'not_fake': 'metadata',
- 'swift': 'metadata'})
+ return {'fake1': 'metadata',
+ 'fake2': 'metadata',
+ 'not_fake': 'metadata',
+ 'swift': 'metadata'}
fake_os = mock.MagicMock()
fake_os.capabilities_client.list_capabilities = fake_list_extensions
self.useFixture(fixtures.MockPatchObject(
diff --git a/tempest/tests/common/test_admin_available.py b/tempest/tests/common/test_admin_available.py
index c3d248c..7b3b1b0 100644
--- a/tempest/tests/common/test_admin_available.py
+++ b/tempest/tests/common/test_admin_available.py
@@ -53,7 +53,7 @@
'password': 'p',
'types': ['admin']})
self.useFixture(fixtures.MockPatch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
+ 'tempest.lib.common.preprov_creds.read_accounts_yaml',
return_value=accounts))
cfg.CONF.set_default('test_accounts_file',
use_accounts_file, group='auth')
diff --git a/tempest/tests/common/test_alt_available.py b/tempest/tests/common/test_alt_available.py
index b9a8967..a425bb8 100644
--- a/tempest/tests/common/test_alt_available.py
+++ b/tempest/tests/common/test_alt_available.py
@@ -40,7 +40,7 @@
project_name="t%s" % ii,
password="p") for ii in creds]
self.useFixture(fixtures.MockPatch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
+ 'tempest.lib.common.preprov_creds.read_accounts_yaml',
return_value=accounts))
cfg.CONF.set_default('test_accounts_file',
use_accounts_file, group='auth')
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/lib/common/test_dynamic_creds.py
similarity index 99%
rename from tempest/tests/common/test_dynamic_creds.py
rename to tempest/tests/lib/common/test_dynamic_creds.py
index cf131eb..6aa7a42 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/lib/common/test_dynamic_creds.py
@@ -17,8 +17,8 @@
from oslo_config import cfg
from tempest.common import credentials_factory as credentials
-from tempest.common import dynamic_creds
from tempest import config
+from tempest.lib.common import dynamic_creds
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.identity.v2 import identity_client as v2_iden_client
@@ -659,7 +659,7 @@
creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
creds.creds_client = mock.MagicMock()
creds.creds_client.create_user_role.side_effect = lib_exc.Conflict
- with mock.patch('tempest.common.dynamic_creds.LOG') as log_mock:
+ with mock.patch('tempest.lib.common.dynamic_creds.LOG') as log_mock:
creds._create_creds()
log_mock.warning.assert_called_once_with(
"Member role already exists, ignoring conflict.")
diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/lib/common/test_preprov_creds.py
similarity index 97%
rename from tempest/tests/common/test_preprov_creds.py
rename to tempest/tests/lib/common/test_preprov_creds.py
index d894c5e..5402e47 100644
--- a/tempest/tests/common/test_preprov_creds.py
+++ b/tempest/tests/lib/common/test_preprov_creds.py
@@ -24,10 +24,10 @@
from oslo_concurrency.fixture import lockutils as lockutils_fixtures
from oslo_config import cfg
-from tempest.common import preprov_creds
from tempest import config
from tempest.lib import auth
from tempest.lib.common import cred_provider
+from tempest.lib.common import preprov_creds
from tempest.lib import exceptions as lib_exc
from tempest.tests import base
from tempest.tests import fake_config
@@ -88,7 +88,7 @@
self.useFixture(lockutils_fixtures.ExternalLockFixture())
self.test_accounts = self._fake_accounts(cfg.CONF.identity.admin_role)
self.accounts_mock = self.useFixture(fixtures.MockPatch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
+ 'tempest.lib.common.preprov_creds.read_accounts_yaml',
return_value=self.test_accounts))
self.useFixture(fixtures.MockPatch(
'os.path.isfile', return_value=True))
@@ -271,7 +271,7 @@
def test_is_not_multi_user(self):
self.test_accounts = [self.test_accounts[0]]
self.useFixture(fixtures.MockPatch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
+ 'tempest.lib.common.preprov_creds.read_accounts_yaml',
return_value=self.test_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
@@ -335,7 +335,7 @@
'password': 'p', 'roles': ['role-7', 'role-11'],
'resources': {'network': 'network-2'}}]
self.useFixture(fixtures.MockPatch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
+ 'tempest.lib.common.preprov_creds.read_accounts_yaml',
return_value=test_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
@@ -363,7 +363,7 @@
admin_accounts = [x for x in self.test_accounts if 'test_admin'
in x['username']]
self.useFixture(fixtures.MockPatch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
+ 'tempest.lib.common.preprov_creds.read_accounts_yaml',
return_value=admin_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
@@ -381,7 +381,7 @@
admin_accounts = [x for x in self.test_accounts if 'test_admin'
in x['username']]
self.useFixture(fixtures.MockPatch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
+ 'tempest.lib.common.preprov_creds.read_accounts_yaml',
return_value=admin_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
@@ -402,7 +402,7 @@
{'username': 'test_admin1', 'tenant_name': 'test_tenant11',
'password': 'p', 'types': ['admin']}]
self.useFixture(fixtures.MockPatch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
+ 'tempest.lib.common.preprov_creds.read_accounts_yaml',
return_value=test_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
@@ -416,7 +416,7 @@
{'username': 'test_admin1', 'tenant_name': 'test_tenant11',
'password': 'p', 'roles': [cfg.CONF.identity.admin_role]}]
self.useFixture(fixtures.MockPatch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
+ 'tempest.lib.common.preprov_creds.read_accounts_yaml',
return_value=test_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
@@ -427,7 +427,7 @@
non_admin_accounts = [x for x in self.test_accounts if 'test_admin'
not in x['username']]
self.useFixture(fixtures.MockPatch(
- 'tempest.common.preprov_creds.read_accounts_yaml',
+ 'tempest.lib.common.preprov_creds.read_accounts_yaml',
return_value=non_admin_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py
index 778c966..924f9f2 100644
--- a/tempest/tests/lib/services/base.py
+++ b/tempest/tests/lib/services/base.py
@@ -32,6 +32,7 @@
def check_service_client_function(self, function, function2mock,
body, to_utf=False, status=200,
headers=None, mock_args=None,
+ resp_as_string=False,
**kwargs):
"""Mock a service client function for unit testing.
@@ -53,6 +54,9 @@
``assert_called_once_with(foo='bar')`` is called.
* If mock_args='foo' then ``assert_called_once_with('foo')``
is called.
+ :param resp_as_string: Whether response body is retruned as string.
+ This is for service client methods which return ResponseBodyData
+ object.
:param kwargs: kwargs that are passed to function.
"""
mocked_response = self.create_response(body, to_utf, status, headers)
@@ -62,8 +66,9 @@
resp = function(**kwargs)
else:
resp = function()
+ if resp_as_string:
+ resp = resp.data
self.assertEqual(body, resp)
-
if isinstance(mock_args, list):
fixture.mock.assert_called_once_with(*mock_args)
elif isinstance(mock_args, dict):
diff --git a/tempest/tests/lib/services/volume/v2/test_limits_client.py b/tempest/tests/lib/services/volume/v2/test_limits_client.py
new file mode 100644
index 0000000..202054c
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_limits_client.py
@@ -0,0 +1,59 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# 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.services.volume.v2 import limits_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestLimitsClient(base.BaseServiceTest):
+
+ FAKE_LIMIT_INFO = {
+ "limits": {
+ "rate": [],
+ "absolute": {
+ "totalSnapshotsUsed": 0,
+ "maxTotalBackups": 10,
+ "maxTotalVolumeGigabytes": 1000,
+ "maxTotalSnapshots": 10,
+ "maxTotalBackupGigabytes": 1000,
+ "totalBackupGigabytesUsed": 0,
+ "maxTotalVolumes": 10,
+ "totalVolumesUsed": 0,
+ "totalBackupsUsed": 0,
+ "totalGigabytesUsed": 0
+ }
+ }
+ }
+
+ def setUp(self):
+ super(TestLimitsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = limits_client.LimitsClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_show_limits(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_limits,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIMIT_INFO,
+ bytes_body)
+
+ def test_show_limits_with_str_body(self):
+ self._test_show_limits()
+
+ def test_show_limits_with_bytes_body(self):
+ self._test_show_limits(bytes_body=True)
diff --git a/tempest/tests/services/object_storage/test_bulk_middleware_client.py b/tempest/tests/services/object_storage/test_bulk_middleware_client.py
new file mode 100644
index 0000000..163b48e
--- /dev/null
+++ b/tempest/tests/services/object_storage/test_bulk_middleware_client.py
@@ -0,0 +1,66 @@
+# Copyright 2017 NEC Corporation. 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.services.object_storage import bulk_middleware_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestBulkMiddlewareClient(base.BaseServiceTest):
+
+ def setUp(self):
+ super(TestBulkMiddlewareClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = bulk_middleware_client.BulkMiddlewareClient(
+ fake_auth, 'object-storage', 'regionOne')
+
+ def test_upload_archive(self):
+ url = 'test_path?extract-archive=tar'
+ data = 'test_data'
+ self.check_service_client_function(
+ self.client.upload_archive,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ {},
+ mock_args=[url, data, {}],
+ resp_as_string=True,
+ upload_path='test_path', data=data, archive_file_format='tar')
+
+ def test_delete_bulk_data(self):
+ url = '?bulk-delete'
+ data = 'test_data'
+ self.check_service_client_function(
+ self.client.delete_bulk_data,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ mock_args=[url, {}, data],
+ resp_as_string=True,
+ data=data)
+
+ def _test_delete_bulk_data_with_post(self, status):
+ url = '?bulk-delete'
+ data = 'test_data'
+ self.check_service_client_function(
+ self.client.delete_bulk_data_with_post,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ {},
+ mock_args=[url, data, {}],
+ resp_as_string=True,
+ status=status,
+ data=data)
+
+ def test_delete_bulk_data_with_post_200(self):
+ self._test_delete_bulk_data_with_post(200)
+
+ def test_delete_bulk_data_with_post_204(self):
+ self._test_delete_bulk_data_with_post(204)
diff --git a/tempest/tests/services/object_storage/test_capabilities_client.py b/tempest/tests/services/object_storage/test_capabilities_client.py
new file mode 100644
index 0000000..5279bf4
--- /dev/null
+++ b/tempest/tests/services/object_storage/test_capabilities_client.py
@@ -0,0 +1,54 @@
+# Copyright 2016 IBM Corp.
+# 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.services.object_storage import capabilities_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestCapabilitiesClient(base.BaseServiceTest):
+
+ def setUp(self):
+ super(TestCapabilitiesClient, self).setUp()
+ self.fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.url = self.fake_auth.base_url(None)
+ self.client = capabilities_client.CapabilitiesClient(
+ self.fake_auth, 'swift', 'region1')
+
+ def _test_list_capabilities(self, bytes_body=False):
+ resp = {
+ "swift": {
+ "version": "1.11.0"
+ },
+ "slo": {
+ "max_manifest_segments": 1000,
+ "max_manifest_size": 2097152,
+ "min_segment_size": 1
+ },
+ "staticweb": {},
+ "tempurl": {}
+ }
+ self.check_service_client_function(
+ self.client.list_capabilities,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ resp,
+ bytes_body)
+
+ def test_list_capabilities_with_str_body(self):
+ self._test_list_capabilities()
+
+ def test_list_capabilities_with_bytes_body(self):
+ self._test_list_capabilities(True)
diff --git a/tempest/tests/test_base_test.py b/tempest/tests/test_base_test.py
index 01b8a72..6c6f612 100644
--- a/tempest/tests/test_base_test.py
+++ b/tempest/tests/test_base_test.py
@@ -16,8 +16,8 @@
from tempest import clients
from tempest.common import credentials_factory as credentials
-from tempest.common import fixed_network
from tempest import config
+from tempest.lib.common import fixed_network
from tempest import test
from tempest.tests import base
from tempest.tests import fake_config