Merge "Support only volume api_v3 is enabled"
diff --git a/.zuul.yaml b/.zuul.yaml
index 0588bc9..44a7f6d 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -16,17 +16,44 @@
- job:
name: tempest-full
parent: devstack-tempest
+ # This currently only works on the master branch.
+ # NOTE(andreaf) Only run on master for now.
+ # The negative lookup is redudant but it's a
+ # reminder that we don't want the job running there.
+ branches: ^(?!driverfixes/)master$
description: |
Base integration test with Neutron networking and py27.
Former names for this job where:
* legacy-tempest-dsvm-neutron-full
* gate-tempest-dsvm-neutron-full-ubuntu-xenial
vars:
- tox_venvlist: full
+ tox_envlist: full
devstack_localrc:
ENABLE_FILE_INJECTION: True
- job:
+ name: tempest-full-py3
+ parent: devstack-tempest
+ branches: ^(?!driverfixes/)master$
+ description: |
+ Base integration test with Neutron networking and py3.
+ Former names for this job where:
+ * legacy-tempest-dsvm-py35
+ * gate-tempest-dsvm-py35
+ vars:
+ tox_envlist: full
+ devstack_localrc:
+ USE_PYTHON3: True
+ FORCE_CONFIG_DRIVE: True
+ devstack_services:
+ s-account: false
+ s-container: false
+ s-object: false
+ s-proxy: false
+ # without Swift, c-bak cannot run (in the Gate at least)
+ c-bak: false
+
+- job:
name: tempest-tox-plugin-sanity-check
parent: tox
description: |
@@ -111,8 +138,7 @@
- ^playbooks/
- ^roles/
- ^.zuul.yaml$
- - tempest-full:
- voting: false
+ - tempest-full-py3:
irrelevant-files:
- ^(test-|)requirements.txt$
- ^.*\.rst$
diff --git a/HACKING.rst b/HACKING.rst
index a3e9c26..f961884 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -385,7 +385,7 @@
Otherwise the bug fix won't be able to land in the project.
-Handily, `Zuul’s cross-repository dependencies
+Handily, `Zuul's cross-repository dependencies
<https://docs.openstack.org/infra/zuul/user/gating.html#cross-project-dependencies>`_.
can be leveraged to do without step 2 and to have steps 3 and 4 happen
"atomically". To do that, make the patch written in step 1 to depend (refer to
diff --git a/doc/requirements.txt b/doc/requirements.txt
new file mode 100644
index 0000000..555b7d2
--- /dev/null
+++ b/doc/requirements.txt
@@ -0,0 +1,6 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
+openstackdocstheme>=1.17.0 # Apache-2.0
+reno>=2.5.0 # Apache-2.0
+sphinx!=1.6.6,>=1.6.2 # BSD
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index e5f70d2..d0d7320 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -400,7 +400,7 @@
Examples:
* Good - ``http://example.com:1234/v2.0``
- * Wouldn’t work - ``http://example.com:1234/xyz/v2.0/``
+ * Wouldn't work - ``http://example.com:1234/xyz/v2.0/``
(adding prefix/suffix around version etc)
Service Feature Configuration
diff --git a/doc/source/library/credential_providers.rst b/doc/source/library/credential_providers.rst
index d96c97a..d25f85c 100644
--- a/doc/source/library/credential_providers.rst
+++ b/doc/source/library/credential_providers.rst
@@ -49,7 +49,7 @@
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,
+ resource_prefix='tempest',
credentials_domain=CONF.auth.default_credentials_domain_name,
admin_role=CONF.identity.admin_role,
identity_uri=CONF.identity.uri_v3,
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index aca1845..9c4ac0b 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -302,6 +302,10 @@
.. _2.2: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id2
+ * `2.6`_
+
+ .. _2.6: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id5
+
* `2.10`_
.. _2.10: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id9
@@ -310,6 +314,10 @@
.. _2.20: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id18
+ * `2.21`_
+
+ .. _2.21: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id19
+
* `2.25`_
.. _2.25: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#maximum-in-mitaka
diff --git a/playbooks/post-tempest.yaml b/playbooks/post-tempest.yaml
index 820e4f6..70dac09 100644
--- a/playbooks/post-tempest.yaml
+++ b/playbooks/post-tempest.yaml
@@ -2,7 +2,6 @@
become: true
vars:
logs_root: "{{ devstack_base_dir|default('/opt/stack') }}"
- stage_dir: "{{ devstack_base_dir|default('/opt/stack') }}"
test_results_stage_name: 'test_results'
roles:
- role: process-test-results
diff --git a/releasenotes/notes/add-group-type-specs-apis-to-v3-group-types-client-10390b52dedede54.yaml b/releasenotes/notes/add-group-type-specs-apis-to-v3-group-types-client-10390b52dedede54.yaml
new file mode 100644
index 0000000..404319d
--- /dev/null
+++ b/releasenotes/notes/add-group-type-specs-apis-to-v3-group-types-client-10390b52dedede54.yaml
@@ -0,0 +1,10 @@
+---
+features:
+ - |
+ Add group type specs APIs to v3 group_types_client library.
+
+ * create_or_update_group_type_specs
+ * list_group_type_specs
+ * show_group_type_specs_item
+ * update_group_type_specs_item
+ * delete_group_type_specs_item
diff --git a/releasenotes/notes/add-show-default-quotas-api-to-network-quotas-client-3a7c1159af9e56ff.yaml b/releasenotes/notes/add-show-default-quotas-api-to-network-quotas-client-3a7c1159af9e56ff.yaml
new file mode 100644
index 0000000..6efe7e6
--- /dev/null
+++ b/releasenotes/notes/add-show-default-quotas-api-to-network-quotas-client-3a7c1159af9e56ff.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add show default quotas API to network quotas_client library.
+ This feature enables the possibility to show default network quotas for
+ a specified project.
diff --git a/releasenotes/notes/cli-tests-v3fixes-fb38189cefd64213.yaml b/releasenotes/notes/cli-tests-v3fixes-fb38189cefd64213.yaml
new file mode 100644
index 0000000..e3443c8
--- /dev/null
+++ b/releasenotes/notes/cli-tests-v3fixes-fb38189cefd64213.yaml
@@ -0,0 +1,9 @@
+---
+other:
+ - |
+ The CLIClient class, when it calls a command line client, uses
+ --os-project-name instead of --os-tenant-name for the project, and
+ passes --os-identity-api-version (default empty).
+ All CLI clients still available in supported releases of OpenStack
+ which are wrapped by the cmd_with_auth() method support those
+ switches.
diff --git a/releasenotes/notes/fix-list-group-snapshots-api-969d9321002c566c.yaml b/releasenotes/notes/fix-list-group-snapshots-api-969d9321002c566c.yaml
index 775a383..a002fb8 100644
--- a/releasenotes/notes/fix-list-group-snapshots-api-969d9321002c566c.yaml
+++ b/releasenotes/notes/fix-list-group-snapshots-api-969d9321002c566c.yaml
@@ -1,6 +1,6 @@
---
fixes:
- |
- Fix list_group_snapshots API in v3 group_snapshots_client: Bug#1715786.
+ Fix list_group_snapshots API in v3 group_snapshots_client: Bug#1715786.
The url path for list group snapshots with details API is changed from
``?detail=True`` to ``/detail``.
diff --git a/releasenotes/notes/removal-deprecated-config-options-3db535b979fe3509.yaml b/releasenotes/notes/removal-deprecated-config-options-3db535b979fe3509.yaml
index dbb6c46..e15d387 100644
--- a/releasenotes/notes/removal-deprecated-config-options-3db535b979fe3509.yaml
+++ b/releasenotes/notes/removal-deprecated-config-options-3db535b979fe3509.yaml
@@ -6,3 +6,7 @@
good to handle them.
* ``[identity-feature-enabled].forbid_global_implied_dsr``
+ * ``[image-feature-enabled].deactivate_image``
+ * ``[default].resources_prefix``
+ * config group ``orchestration``
+ * ``[service_available].heat``
diff --git a/requirements.txt b/requirements.txt
index cd74449..c02cd05 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,9 +8,9 @@
paramiko>=2.0.0 # LGPLv2.1+
netaddr>=0.7.18 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
-oslo.concurrency>=3.20.0 # Apache-2.0
+oslo.concurrency>=3.25.0 # Apache-2.0
oslo.config>=5.1.0 # Apache-2.0
-oslo.log>=3.30.0 # Apache-2.0
+oslo.log>=3.36.0 # Apache-2.0
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
oslo.utils>=3.33.0 # Apache-2.0
six>=1.10.0 # MIT
diff --git a/roles/process-stackviz/README.rst b/roles/process-stackviz/README.rst
index b05326d..54c217b 100644
--- a/roles/process-stackviz/README.rst
+++ b/roles/process-stackviz/README.rst
@@ -11,7 +11,7 @@
The devstack base directory.
.. zuul:rolevar:: stage_dir
- :default: /opt/stack/logs
+ :default: "{{ ansible_user_dir }}"
The stage directory where the input data can be found and
the output will be produced.
diff --git a/roles/process-stackviz/defaults/main.yaml b/roles/process-stackviz/defaults/main.yaml
index b1eb8d9..c6a64d1 100644
--- a/roles/process-stackviz/defaults/main.yaml
+++ b/roles/process-stackviz/defaults/main.yaml
@@ -1,3 +1,3 @@
devstack_base_dir: /opt/stack
-stage_dir: /opt/stack/
+stage_dir: "{{ ansible_user_dir }}"
test_results_stage_name: test_results
diff --git a/roles/run-tempest/README.rst b/roles/run-tempest/README.rst
index b5defb7..33dcce9 100644
--- a/roles/run-tempest/README.rst
+++ b/roles/run-tempest/README.rst
@@ -29,7 +29,7 @@
# Line with only a comment.
(tempest\.(api|scenario|thirdparty)).*$ # Run only api scenario and third party
-.. zuul:rolevar:: tox_venvlist
+.. zuul:rolevar:: tox_envlist
:default: smoke
The Tempest tox environment to run.
diff --git a/roles/run-tempest/defaults/main.yaml b/roles/run-tempest/defaults/main.yaml
index 3e57511..85e94f2 100644
--- a/roles/run-tempest/defaults/main.yaml
+++ b/roles/run-tempest/defaults/main.yaml
@@ -1,3 +1,3 @@
devstack_base_dir: /opt/stack
tempest_test_regex: ''
-tox_venvlist: smoke
+tox_envlist: smoke
diff --git a/roles/run-tempest/tasks/main.yaml b/roles/run-tempest/tasks/main.yaml
index 297cd72..87898db 100644
--- a/roles/run-tempest/tasks/main.yaml
+++ b/roles/run-tempest/tasks/main.yaml
@@ -21,7 +21,7 @@
when: num_cores|int > 3
- name: Run Tempest
- command: tox -e {{tox_venvlist}} -- {{tempest_test_regex|quote}} --concurrency={{tempest_concurrency|default(default_concurrency)}}
+ command: tox -e {{tox_envlist}} -- {{tempest_test_regex|quote}} --concurrency={{tempest_concurrency|default(default_concurrency)}}
args:
chdir: "{{devstack_base_dir}}/tempest"
become: true
diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py
index a9772c4..c4d5768 100644
--- a/tempest/api/compute/admin/test_auto_allocate_network.py
+++ b/tempest/api/compute/admin/test_auto_allocate_network.py
@@ -84,8 +84,7 @@
nets = cls.networks_client.list_networks(
**search_opts).get('networks', [])
if nets:
- raise lib_excs.TempestException(
- 'Found shared networks: %s' % nets)
+ raise cls.skipException('Found shared networks: %s' % nets)
@classmethod
def resource_cleanup(cls):
diff --git a/tempest/api/compute/admin/test_create_server.py b/tempest/api/compute/admin/test_create_server.py
index 08b2d19..711b441 100644
--- a/tempest/api/compute/admin/test_create_server.py
+++ b/tempest/api/compute/admin/test_create_server.py
@@ -56,6 +56,18 @@
# Create a flavor with ephemeral disk
flavor = self.create_flavor(name=flavor_name, ram=ram, vcpus=vcpus,
disk=disk, ephemeral=ephem_disk)
+
+ # Set extra specs same as self.flavor_ref for the created flavor,
+ # because the environment may need some special extra specs to
+ # create server which should have been contained in
+ # self.flavor_ref.
+ extra_spec_keys = \
+ self.admin_flavors_client.list_flavor_extra_specs(
+ self.flavor_ref)['extra_specs']
+ if extra_spec_keys:
+ self.admin_flavors_client.set_flavor_extra_spec(
+ flavor['id'], **extra_spec_keys)
+
return flavor['id']
flavor_with_eph_disk_id = create_flavor_with_ephemeral(ephem_disk=1)
diff --git a/tempest/api/compute/admin/test_keypairs_v210.py b/tempest/api/compute/admin/test_keypairs_v210.py
index e24c7c1..24ea8a1 100644
--- a/tempest/api/compute/admin/test_keypairs_v210.py
+++ b/tempest/api/compute/admin/test_keypairs_v210.py
@@ -34,7 +34,8 @@
k_name = data_utils.rand_name('keypair')
keypair = self.create_keypair(k_name,
keypair_type='ssh',
- user_id=user_id)
+ user_id=user_id,
+ client=self.client)
self.assertEqual(k_name, keypair['name'],
"The created keypair name is not equal "
"to the requested name!")
@@ -56,7 +57,8 @@
self.assertEqual(user_id, keypair_detail['user_id'],
"The fetched keypair is not for requested user!")
# Create a admin keypair
- admin_keypair = self.create_keypair(keypair_type='ssh')
+ admin_keypair = self.create_keypair(keypair_type='ssh',
+ client=self.client)
admin_keypair.pop('private_key', None)
admin_keypair.pop('user_id')
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index dcd7b9b..9e897e3 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -230,8 +230,8 @@
while data not in console_output and t <= 120.0:
try:
ws.send_frame(data)
- recieved = ws.receive_frame()
- console_output += recieved
+ received = ws.receive_frame()
+ console_output += received
except Exception:
# In case we had an issue with send/receive on the
# websocket connection, we create a new one.
diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py
index a626ebb..a6b71b2 100644
--- a/tempest/api/compute/admin/test_migrations.py
+++ b/tempest/api/compute/admin/test_migrations.py
@@ -77,6 +77,16 @@
)['flavor']
self.addCleanup(self._flavor_clean_up, flavor['id'])
+ # Set extra specs same as self.flavor_ref for the created flavor,
+ # because the environment may need some special extra specs to
+ # create server which should have been contained in
+ # self.flavor_ref.
+ extra_spec_keys = self.admin_flavors_client.list_flavor_extra_specs(
+ self.flavor_ref)['extra_specs']
+ if extra_spec_keys:
+ self.admin_flavors_client.set_flavor_extra_spec(
+ flavor['id'], **extra_spec_keys)
+
# Now boot a server with the copied flavor.
server = self.create_test_server(
wait_until='ACTIVE', flavor=flavor['id'])
diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py
index acb0d90..87ce39d 100644
--- a/tempest/api/compute/admin/test_networks.py
+++ b/tempest/api/compute/admin/test_networks.py
@@ -24,7 +24,7 @@
"""Tests Nova Networks API that usually requires admin privileges.
API docs:
- http://developer.openstack.org/api-ref-compute-v2-ext.html#ext-os-networks
+ https://developer.openstack.org/api-ref/compute/#networks-os-networks-deprecated
"""
@classmethod
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index ac03cdc..9759be7 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -99,6 +99,15 @@
cls.versions_client = cls.os_primary.compute_versions_client
if CONF.service_available.cinder:
cls.volumes_client = cls.os_primary.volumes_client_latest
+ if CONF.service_available.glance:
+ if CONF.image_feature_enabled.api_v1:
+ cls.images_client = cls.os_primary.image_client
+ elif CONF.image_feature_enabled.api_v2:
+ cls.images_client = cls.os_primary.image_client_v2
+ else:
+ raise lib_exc.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
@classmethod
def resource_setup(cls):
@@ -176,11 +185,12 @@
cls.request_microversion)
v2_37_version = api_version_request.APIVersionRequest('2.37')
+ tenant_network = cls.get_tenant_network()
# NOTE(snikitin): since microversion v2.37 'networks' field is required
- if request_version >= v2_37_version and 'networks' not in kwargs:
+ if (request_version >= v2_37_version and 'networks' not in kwargs and
+ not tenant_network):
kwargs['networks'] = 'none'
- tenant_network = cls.get_tenant_network()
body, servers = compute.create_test_server(
cls.os_primary,
validatable,
@@ -254,7 +264,11 @@
@classmethod
def create_image_from_server(cls, server_id, **kwargs):
- """Wrapper utility that returns an image created from the server."""
+ """Wrapper utility that returns an image created from the server.
+
+ If compute microversion >= 2.36, the returned image response will
+ be from the image service API rather than the compute image proxy API.
+ """
name = kwargs.pop('name',
data_utils.rand_name(cls.__name__ + "-image"))
wait_until = kwargs.pop('wait_until', None)
@@ -267,14 +281,21 @@
image_id = image['image_id']
else:
image_id = data_utils.parse_image_id(image.response['location'])
+
+ # The compute image proxy APIs were deprecated in 2.35 so
+ # use the images client directly if the API microversion being
+ # used is >=2.36.
+ if api_version_utils.compare_version_header_to_response(
+ "OpenStack-API-Version", "compute 2.36", image.response, "lt"):
+ client = cls.images_client
+ else:
+ client = cls.compute_images_client
cls.addClassResourceCleanup(test_utils.call_and_ignore_notfound_exc,
- cls.compute_images_client.delete_image,
- image_id)
+ client.delete_image, image_id)
if wait_until is not None:
try:
- waiters.wait_for_image_status(cls.compute_images_client,
- image_id, wait_until)
+ waiters.wait_for_image_status(client, image_id, wait_until)
except lib_exc.NotFound:
if wait_until.upper() == 'ACTIVE':
# If the image is not found after create_image returned
@@ -292,7 +313,11 @@
image_id=image_id)
else:
raise
- image = cls.compute_images_client.show_image(image_id)['image']
+ image = client.show_image(image_id)
+ # Compute image client returns response wrapped in 'image' element
+ # which is not the case with Glance image client.
+ if 'image' in image:
+ image = image['image']
if wait_until.upper() == 'ACTIVE':
if wait_for_server:
@@ -352,6 +377,13 @@
'VERIFY_RESIZE')
cls.servers_client.confirm_resize_server(server_id)
waiters.wait_for_server_status(cls.servers_client, server_id, 'ACTIVE')
+ server = cls.servers_client.show_server(server_id)['server']
+ # Nova API > 2.46 no longer includes flavor.id
+ if server['flavor'].get('id'):
+ if new_flavor_id != server['flavor']['id']:
+ msg = ('Flavor id of %s is not equal to new_flavor_id.'
+ % server_id)
+ raise lib_exc.TempestException(msg)
@classmethod
def delete_volume(cls, volume_id):
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
index efd4f0e..3a474e6 100644
--- a/tempest/api/compute/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -30,18 +30,6 @@
class FlavorsV2NegativeTest(base.BaseV2ComputeTest):
- @classmethod
- def setup_clients(cls):
- super(FlavorsV2NegativeTest, cls).setup_clients()
- if CONF.image_feature_enabled.api_v1:
- cls.images_client = cls.os_primary.image_client
- elif CONF.image_feature_enabled.api_v2:
- cls.images_client = cls.os_primary.image_client_v2
- else:
- raise lib_exc.InvalidConfiguration(
- 'Either api_v1 or api_v2 must be True in '
- '[image-feature-enabled].')
-
@decorators.attr(type=['negative'])
@utils.services('image')
@decorators.idempotent_id('90f0d93a-91c1-450c-91e6-07d18172cefe')
diff --git a/tempest/api/compute/keypairs/base.py b/tempest/api/compute/keypairs/base.py
index 0051810..44da88c 100644
--- a/tempest/api/compute/keypairs/base.py
+++ b/tempest/api/compute/keypairs/base.py
@@ -20,17 +20,16 @@
class BaseKeypairTest(base.BaseV2ComputeTest):
"""Base test case class for all keypair API tests."""
- @classmethod
- def setup_clients(cls):
- super(BaseKeypairTest, cls).setup_clients()
- cls.client = cls.keypairs_client
-
- def _delete_keypair(self, keypair_name, **params):
- self.client.delete_keypair(keypair_name, **params)
+ def _delete_keypair(self, keypair_name, client=None, **params):
+ if not client:
+ client = self.keypairs_client
+ client.delete_keypair(keypair_name, **params)
def create_keypair(self, keypair_name=None,
pub_key=None, keypair_type=None,
- user_id=None):
+ user_id=None, client=None):
+ if not client:
+ client = self.keypairs_client
if keypair_name is None:
keypair_name = data_utils.rand_name(
self.__class__.__name__ + '-keypair')
@@ -43,6 +42,7 @@
if user_id:
kwargs.update({'user_id': user_id})
delete_params['user_id'] = user_id
- body = self.client.create_keypair(**kwargs)['keypair']
- self.addCleanup(self._delete_keypair, keypair_name, **delete_params)
+ body = client.create_keypair(**kwargs)['keypair']
+ self.addCleanup(self._delete_keypair, keypair_name,
+ client, **delete_params)
return body
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 3a54d51..66abb21 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -35,7 +35,7 @@
key_list.append(keypair)
# Fetch all keypairs and verify the list
# has all created keypairs
- fetched_list = self.client.list_keypairs()['keypairs']
+ fetched_list = self.keypairs_client.list_keypairs()['keypairs']
new_list = list()
for keypair in fetched_list:
new_list.append(keypair['keypair'])
@@ -61,7 +61,7 @@
# Keypair should be created, Got details by name and deleted
k_name = data_utils.rand_name('keypair')
self.create_keypair(k_name)
- keypair_detail = self.client.show_keypair(k_name)['keypair']
+ keypair_detail = self.keypairs_client.show_keypair(k_name)['keypair']
self.assertEqual(keypair_detail['name'], k_name,
"The created keypair name is not equal "
"to requested name")
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index 205076c..f9050a8 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -34,7 +34,8 @@
def test_keypair_delete_nonexistent_key(self):
# Non-existent key deletion should throw a proper error
k_name = data_utils.rand_name("keypair-non-existent")
- self.assertRaises(lib_exc.NotFound, self.client.delete_keypair,
+ self.assertRaises(lib_exc.NotFound,
+ self.keypairs_client.delete_keypair,
k_name)
@decorators.attr(type=['negative'])
@@ -58,11 +59,11 @@
def test_create_keypair_with_duplicate_name(self):
# Keypairs with duplicate names should not be created
k_name = data_utils.rand_name('keypair')
- self.client.create_keypair(name=k_name)
+ self.keypairs_client.create_keypair(name=k_name)
# Now try the same keyname to create another key
self.assertRaises(lib_exc.Conflict, self.create_keypair,
k_name)
- self.client.delete_keypair(k_name)
+ self.keypairs_client.delete_keypair(k_name)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('1398abe1-4a84-45fb-9294-89f514daff00')
diff --git a/tempest/api/compute/keypairs/test_keypairs_v22.py b/tempest/api/compute/keypairs/test_keypairs_v22.py
index f39bb12..1aff262 100644
--- a/tempest/api/compute/keypairs/test_keypairs_v22.py
+++ b/tempest/api/compute/keypairs/test_keypairs_v22.py
@@ -32,9 +32,9 @@
# Verify whether 'type' is present in keypair create response of
# version 2.2 and it is with default value 'ssh'.
self._check_keypair_type(keypair, keypair_type)
- keypair_detail = self.client.show_keypair(k_name)['keypair']
+ keypair_detail = self.keypairs_client.show_keypair(k_name)['keypair']
self._check_keypair_type(keypair_detail, keypair_type)
- fetched_list = self.client.list_keypairs()['keypairs']
+ fetched_list = self.keypairs_client.list_keypairs()['keypairs']
for keypair in fetched_list:
# Verify whether 'type' is present in keypair list response of
# version 2.2 and it is with default value 'ssh'.
diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py
index a126fd6..d857fcb 100644
--- a/tempest/api/compute/servers/test_device_tagging.py
+++ b/tempest/api/compute/servers/test_device_tagging.py
@@ -139,6 +139,7 @@
server = self.create_test_server(
validatable=True,
+ wait_until='ACTIVE',
validation_resources=validation_resources,
config_drive=config_drive_enabled,
adminPass=admin_pass,
@@ -205,6 +206,7 @@
self.addCleanup(self.delete_server, server['id'])
+ server = self.servers_client.show_server(server['id'])['server']
self.ssh_client = remote_client.RemoteClient(
self.get_server_ip(server, validation_resources),
CONF.validation.image_ssh_user,
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 6c9b287..393e68f 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -119,8 +119,12 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('74745ad8-b346-45b5-b9b8-509d7447fc1f')
def test_list_servers_by_changes_since_future_date(self):
- # Return an empty list when a date in the future is passed
- changes_since = {'changes-since': '2051-01-01T12:34:00Z'}
+ # Return an empty list when a date in the future is passed.
+ # updated_at field may haven't been set at the point in the boot
+ # process where build_request still exists, so add
+ # {'status': 'ACTIVE'} along with changes-since as filter.
+ changes_since = {'changes-since': '2051-01-01T12:34:00Z',
+ 'status': 'ACTIVE'}
body = self.client.list_servers(**changes_since)
self.assertEmpty(body['servers'])
diff --git a/tempest/api/compute/servers/test_server_password.py b/tempest/api/compute/servers/test_server_password.py
index e7591a5..e6a668a 100644
--- a/tempest/api/compute/servers/test_server_password.py
+++ b/tempest/api/compute/servers/test_server_password.py
@@ -21,19 +21,14 @@
class ServerPasswordTestJSON(base.BaseV2ComputeTest):
@classmethod
- def setup_clients(cls):
- super(ServerPasswordTestJSON, cls).setup_clients()
- cls.client = cls.servers_client
-
- @classmethod
def resource_setup(cls):
super(ServerPasswordTestJSON, cls).resource_setup()
cls.server = cls.create_test_server(wait_until="ACTIVE")
@decorators.idempotent_id('f83b582f-62a8-4f22-85b0-0dee50ff783a')
def test_get_server_password(self):
- self.client.show_password(self.server['id'])
+ self.servers_client.show_password(self.server['id'])
@decorators.idempotent_id('f8229e8b-b625-4493-800a-bde86ac611ea')
def test_delete_server_password(self):
- self.client.delete_password(self.server['id'])
+ self.servers_client.delete_password(self.server['id'])
diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
index 20923a8..c4e2400 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -28,11 +28,6 @@
cls.set_network_resources()
super(VirtualInterfacesNegativeTestJSON, cls).setup_credentials()
- @classmethod
- def setup_clients(cls):
- super(VirtualInterfacesNegativeTestJSON, cls).setup_clients()
- cls.client = cls.servers_client
-
@decorators.attr(type=['negative'])
@decorators.idempotent_id('64ebd03c-1089-4306-93fa-60f5eb5c803c')
@utils.services('network')
@@ -41,5 +36,5 @@
# for an invalid server_id
invalid_server_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound,
- self.client.list_virtual_interfaces,
+ self.servers_client.list_virtual_interfaces,
invalid_server_id)
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 297e8a8..e6184b7 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -23,12 +23,12 @@
CONF = config.CONF
-class AttachVolumeTestJSON(base.BaseV2ComputeTest):
- max_microversion = '2.19'
+class BaseAttachVolumeTest(base.BaseV2ComputeTest):
+ """Base class for the attach volume tests in this module."""
@classmethod
def skip_checks(cls):
- super(AttachVolumeTestJSON, cls).skip_checks()
+ super(BaseAttachVolumeTest, cls).skip_checks()
if not CONF.service_available.cinder:
skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
raise cls.skipException(skip_msg)
@@ -36,11 +36,11 @@
@classmethod
def setup_credentials(cls):
cls.prepare_instance_network()
- super(AttachVolumeTestJSON, cls).setup_credentials()
+ super(BaseAttachVolumeTest, cls).setup_credentials()
@classmethod
def resource_setup(cls):
- super(AttachVolumeTestJSON, cls).resource_setup()
+ super(BaseAttachVolumeTest, cls).resource_setup()
cls.device = CONF.compute.volume_device_name
def _create_server(self):
@@ -58,6 +58,9 @@
server['id'])['addresses']
return server, validation_resources
+
+class AttachVolumeTestJSON(BaseAttachVolumeTest):
+
@decorators.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff')
def test_attach_detach_volume(self):
# Stop and Start a server with an attached volume, ensuring that
@@ -149,7 +152,7 @@
self.volumes_client, attachment['volumeId'], 'available')
-class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
+class AttachVolumeShelveTestJSON(BaseAttachVolumeTest):
"""Testing volume with shelved instance.
This test checks the attaching and detaching volumes from
diff --git a/tempest/api/identity/admin/v2/test_tokens.py b/tempest/api/identity/admin/v2/test_tokens.py
index 6b30d23..6ce1a8b 100644
--- a/tempest/api/identity/admin/v2/test_tokens.py
+++ b/tempest/api/identity/admin/v2/test_tokens.py
@@ -112,6 +112,8 @@
@decorators.idempotent_id('ca3ea6f7-ed08-4a61-adbd-96906456ad31')
def test_list_endpoints_for_token(self):
+ tempest_services = ['keystone', 'nova', 'neutron', 'swift', 'cinder',
+ 'neutron']
# get a token for the user
creds = self.os_primary.credentials
username = creds.username
@@ -125,9 +127,10 @@
self.assertIsInstance(endpoints, list)
# Store list of service names
service_names = [e['name'] for e in endpoints]
- # Get the list of available services.
+ # Get the list of available services. Keystone is always available.
available_services = [s[0] for s in list(
- CONF.service_available.items()) if s[1] is True]
+ CONF.service_available.items()) if s[1] is True] + ['keystone']
# Verify that all available services are present.
- for service in available_services:
- self.assertIn(service, service_names)
+ for service in tempest_services:
+ if service in available_services:
+ self.assertIn(service, service_names)
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index c846f88..ce5bd3e 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -18,8 +18,6 @@
import six
-import testtools
-
from oslo_log import log as logging
from tempest.api.image import base
from tempest import config
@@ -128,8 +126,6 @@
self.assertEqual(image['id'], body['id'])
self.assertEqual(new_image_name, body['name'])
- @testtools.skipUnless(CONF.image_feature_enabled.deactivate_image,
- 'deactivate-image is not available.')
@decorators.idempotent_id('951ebe01-969f-4ea9-9898-8a3f1f442ab0')
def test_deactivate_reactivate_image(self):
# Create image
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index 1a7b0ec..206d867 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -51,7 +51,8 @@
agents = cls.admin_agents_client.list_agents(
agent_type=AGENT_TYPE)['agents']
for agent in agents:
- if agent['configurations']['agent_mode'] in AGENT_MODES:
+ if (agent['configurations']['agent_mode'] in AGENT_MODES and
+ agent['alive']):
cls.agent = agent
break
else:
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index cf4236d..57a28bf 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -80,6 +80,10 @@
non_default_quotas = self.admin_quotas_client.list_quotas()
for q in non_default_quotas['quotas']:
self.assertNotEqual(project_id, q['tenant_id'])
+ quota_set = self.admin_quotas_client.show_quotas(project_id)['quota']
+ default_quotas = self.admin_quotas_client.show_default_quotas(
+ project_id)['quota']
+ self.assertEqual(default_quotas, quota_set)
@decorators.idempotent_id('2390f766-836d-40ef-9aeb-e810d78207fb')
def test_quotas(self):
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index ee72163..e8f3f8b 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -36,10 +36,14 @@
using HA proxy sync the deletion properly, otherwise, the container
might fail to be deleted because it's not empty.
- :param containers: List of containers to be deleted
+ :param containers: List of containers(or string of a container)
+ to be deleted
:param container_client: Client to be used to delete containers
:param object_client: Client to be used to delete objects
"""
+ if isinstance(containers, str):
+ containers = [containers]
+
for cont in containers:
try:
params = {'limit': 9999, 'format': 'json'}
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 3bbab11..c5c30e3 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -241,7 +241,7 @@
@decorators.idempotent_id('365e6fc7-1cfe-463b-a37c-8bd08d47b6aa')
def test_list_containers_with_prefix(self):
# list containers that have a name that starts with a prefix
- prefix = '{0}-a'.format(CONF.resources_prefix)
+ prefix = 'tempest-a'
params = {'prefix': prefix}
resp, container_list = self.account_client.list_account_containers(
params=params)
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 2e979bc..322579c 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -71,14 +71,12 @@
(cls.container_client_alt, cls.object_client_alt)
for cont_name, client in cls.clients.items():
client[0].create_container(cont_name)
+ cls.addClassResourceCleanup(base.delete_containers,
+ cont_name,
+ client[0],
+ client[1])
cls.containers.append(cont_name)
- @classmethod
- def resource_cleanup(cls):
- for client in cls.clients.values():
- cls.delete_containers(client[0], client[1])
- super(ContainerSyncTest, cls).resource_cleanup()
-
def _test_container_synchronization(self, make_headers):
# container to container synchronization
# to allow/accept sync requests to/from other accounts
diff --git a/tempest/api/volume/admin/test_group_type_specs.py b/tempest/api/volume/admin/test_group_type_specs.py
new file mode 100644
index 0000000..c5e6d1a
--- /dev/null
+++ b/tempest/api/volume/admin/test_group_type_specs.py
@@ -0,0 +1,80 @@
+# 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.api.volume import base
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+
+class GroupTypeSpecsTest(base.BaseVolumeAdminTest):
+ _api_version = 3
+ min_microversion = '3.11'
+ max_microversion = 'latest'
+
+ @decorators.idempotent_id('bb4e30d0-de6e-4f4d-866c-dcc48d023b4e')
+ def test_group_type_specs_create_show_update_list_delete(self):
+ # Create new group type
+ group_type = self.create_group_type()
+
+ # Create new group type specs
+ create_specs = {
+ "key1": "value1",
+ "key2": "value2"
+ }
+ body = self.admin_group_types_client.create_or_update_group_type_specs(
+ group_type['id'], create_specs)['group_specs']
+ self.assertEqual(create_specs, body)
+
+ # Create a new group type spec and update an existing group type spec
+ update_specs = {
+ "key2": "value2-updated",
+ "key3": "value3"
+ }
+ body = self.admin_group_types_client.create_or_update_group_type_specs(
+ group_type['id'], update_specs)['group_specs']
+ self.assertEqual(update_specs, body)
+
+ # Show specified item of group type specs
+ spec_keys = ['key2', 'key3']
+ for key in spec_keys:
+ body = self.admin_group_types_client.show_group_type_specs_item(
+ group_type['id'], key)
+ self.assertIn(key, body)
+ self.assertEqual(update_specs[key], body[key])
+
+ # Update specified item of group type specs
+ update_key = 'key3'
+ update_spec = {update_key: "value3-updated"}
+ body = self.admin_group_types_client.update_group_type_specs_item(
+ group_type['id'], update_key, update_spec)
+ self.assertEqual(update_spec, body)
+
+ # List all group type specs that created or updated above
+ list_specs = {}
+ list_specs.update(create_specs)
+ list_specs.update(update_specs)
+ list_specs.update(update_spec)
+ body = self.admin_group_types_client.list_group_type_specs(
+ group_type['id'])['group_specs']
+ self.assertEqual(list_specs, body)
+
+ # Delete specified item of group type specs
+ delete_key = 'key1'
+ self.admin_group_types_client.delete_group_type_specs_item(
+ group_type['id'], delete_key)
+ self.assertRaises(
+ lib_exc.NotFound,
+ self.admin_group_types_client.show_group_type_specs_item,
+ group_type['id'], delete_key)
diff --git a/tempest/api/volume/admin/test_snapshot_manage.py b/tempest/api/volume/admin/test_snapshot_manage.py
index 3b21b28..37a47ec 100644
--- a/tempest/api/volume/admin/test_snapshot_manage.py
+++ b/tempest/api/volume/admin/test_snapshot_manage.py
@@ -63,7 +63,7 @@
# Verify the original snapshot does not exist in snapshot list
params = {'all_tenants': 1}
all_snapshots = self.admin_snapshots_client.list_snapshots(
- detail=True, params=params)['snapshots']
+ detail=True, **params)['snapshots']
self.assertNotIn(snapshot['id'], [v['id'] for v in all_snapshots])
# Manage the snapshot
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index 42bfcd6..6f9daa8 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -38,7 +38,6 @@
def setup_credentials(cls):
super(BaseVolumeQuotasAdminTestJSON, cls).setup_credentials()
cls.demo_tenant_id = cls.os_primary.credentials.tenant_id
- cls.alt_client = cls.os_alt.volumes_client_latest
@classmethod
def setup_clients(cls):
@@ -150,7 +149,8 @@
self.demo_tenant_id, params={'usage': True})['quota_set']
alt_quota = self.admin_quotas_client.show_quota_set(
- self.alt_client.tenant_id, params={'usage': True})['quota_set']
+ self.os_alt.volumes_client_latest.tenant_id,
+ params={'usage': True})['quota_set']
# Creates a volume transfer
transfer = self.transfer_client.create_volume_transfer(
@@ -164,14 +164,15 @@
# Verify volume transferred is available
waiters.wait_for_volume_resource_status(
- self.alt_client, volume['id'], 'available')
+ self.os_alt.volumes_client_latest, volume['id'], 'available')
# List of tenants quota usage post transfer
new_primary_quota = self.admin_quotas_client.show_quota_set(
self.demo_tenant_id, params={'usage': True})['quota_set']
new_alt_quota = self.admin_quotas_client.show_quota_set(
- self.alt_client.tenant_id, params={'usage': True})['quota_set']
+ self.os_alt.volumes_client_latest.tenant_id,
+ params={'usage': True})['quota_set']
# Verify tenants quota usage was updated
self.assertEqual(primary_quota['volumes']['in_use'] -
diff --git a/tempest/api/volume/admin/test_volume_type_access.py b/tempest/api/volume/admin/test_volume_type_access.py
index e93bcb5..b64face 100644
--- a/tempest/api/volume/admin/test_volume_type_access.py
+++ b/tempest/api/volume/admin/test_volume_type_access.py
@@ -27,11 +27,6 @@
credentials = ['primary', 'alt', 'admin']
- @classmethod
- def setup_clients(cls):
- super(VolumeTypesAccessTest, cls).setup_clients()
- cls.alt_client = cls.os_alt.volumes_client_latest
-
@decorators.idempotent_id('d4dd0027-835f-4554-a6e5-50903fb79184')
def test_volume_type_access_add(self):
# Creating a NON public volume type
@@ -70,10 +65,11 @@
# Adding volume type access for alt tenant
self.admin_volume_types_client.add_type_access(
- volume_type['id'], project=self.alt_client.tenant_id)
+ volume_type['id'],
+ project=self.os_alt.volumes_client_latest.tenant_id)
self.addCleanup(self.admin_volume_types_client.remove_type_access,
volume_type['id'],
- project=self.alt_client.tenant_id)
+ project=self.os_alt.volumes_client_latest.tenant_id)
# List tenant access for the given volume type
type_access_list = self.admin_volume_types_client.list_type_access(
@@ -88,5 +84,5 @@
# Validating the permitted tenants are the expected tenants
self.assertIn(self.volumes_client.tenant_id,
map(operator.itemgetter('project_id'), type_access_list))
- self.assertIn(self.alt_client.tenant_id,
+ self.assertIn(self.os_alt.volumes_client_latest.tenant_id,
map(operator.itemgetter('project_id'), type_access_list))
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 107ff57..81fd6e6 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -106,20 +106,12 @@
cls.min_microversion,
CONF.volume.min_microversion))
- cls.snapshots = []
- cls.volumes = []
cls.image_ref = CONF.compute.image_ref
cls.flavor_ref = CONF.compute.flavor_ref
cls.build_interval = CONF.volume.build_interval
cls.build_timeout = CONF.volume.build_timeout
@classmethod
- def resource_cleanup(cls):
- cls.clear_snapshots()
- cls.clear_volumes()
- super(BaseVolumeTest, cls).resource_cleanup()
-
- @classmethod
def create_volume(cls, wait_until='available', **kwargs):
"""Wrapper utility that returns a test volume.
@@ -138,7 +130,9 @@
kwargs['name'] = name
volume = cls.volumes_client.create_volume(**kwargs)['volume']
- cls.volumes.append(volume)
+ cls.addClassResourceCleanup(test_utils.call_and_ignore_notfound_exc,
+ cls.delete_volume, cls.volumes_client,
+ volume['id'])
waiters.wait_for_volume_resource_status(cls.volumes_client,
volume['id'], wait_until)
return volume
@@ -152,7 +146,8 @@
snapshot = cls.snapshots_client.create_snapshot(
volume_id=volume_id, **kwargs)['snapshot']
- cls.snapshots.append(snapshot['id'])
+ cls.addClassResourceCleanup(test_utils.call_and_ignore_notfound_exc,
+ cls.delete_snapshot, snapshot['id'])
waiters.wait_for_volume_resource_status(cls.snapshots_client,
snapshot['id'], 'available')
return snapshot
@@ -181,14 +176,13 @@
client.delete_volume(volume_id)
client.wait_for_resource_deletion(volume_id)
- def delete_snapshot(self, snapshot_id, snapshots_client=None):
+ @classmethod
+ def delete_snapshot(cls, snapshot_id, snapshots_client=None):
"""Delete snapshot by the given client"""
if snapshots_client is None:
- snapshots_client = self.snapshots_client
+ snapshots_client = cls.snapshots_client
snapshots_client.delete_snapshot(snapshot_id)
snapshots_client.wait_for_resource_deletion(snapshot_id)
- if snapshot_id in self.snapshots:
- self.snapshots.remove(snapshot_id)
def attach_volume(self, server_id, volume_id):
"""Attach a volume to a server"""
@@ -202,31 +196,6 @@
self.addCleanup(self.servers_client.detach_volume, server_id,
volume_id)
- @classmethod
- def clear_volumes(cls):
- for volume in cls.volumes:
- try:
- cls.volumes_client.delete_volume(volume['id'])
- except Exception:
- pass
-
- for volume in cls.volumes:
- try:
- cls.volumes_client.wait_for_resource_deletion(volume['id'])
- except Exception:
- pass
-
- @classmethod
- def clear_snapshots(cls):
- for snapshot in cls.snapshots:
- test_utils.call_and_ignore_notfound_exc(
- cls.snapshots_client.delete_snapshot, snapshot)
-
- for snapshot in cls.snapshots:
- test_utils.call_and_ignore_notfound_exc(
- cls.snapshots_client.wait_for_resource_deletion,
- snapshot)
-
def create_server(self, wait_until='ACTIVE', **kwargs):
name = kwargs.pop(
'name',
@@ -308,26 +277,13 @@
cls.os_admin.volume_scheduler_stats_v2_client
@classmethod
- def resource_setup(cls):
- super(BaseVolumeAdminTest, cls).resource_setup()
-
- cls.qos_specs = []
- cls.volume_types = []
-
- @classmethod
- def resource_cleanup(cls):
- cls.clear_qos_specs()
- super(BaseVolumeAdminTest, cls).resource_cleanup()
- cls.clear_volume_types()
-
- @classmethod
def create_test_qos_specs(cls, name=None, consumer=None, **kwargs):
"""create a test Qos-Specs."""
name = name or data_utils.rand_name(cls.__name__ + '-QoS')
consumer = consumer or 'front-end'
qos_specs = cls.admin_volume_qos_client.create_qos(
name=name, consumer=consumer, **kwargs)['qos_specs']
- cls.qos_specs.append(qos_specs['id'])
+ cls.addClassResourceCleanup(cls.clear_qos_spec, qos_specs['id'])
return qos_specs
@classmethod
@@ -336,7 +292,7 @@
name = name or data_utils.rand_name(cls.__name__ + '-volume-type')
volume_type = cls.admin_volume_types_client.create_volume_type(
name=name, **kwargs)['volume_type']
- cls.volume_types.append(volume_type['id'])
+ cls.addClassResourceCleanup(cls.clear_volume_type, volume_type['id'])
return volume_type
def create_group_type(self, name=None, **kwargs):
@@ -350,22 +306,18 @@
return group_type
@classmethod
- def clear_qos_specs(cls):
- for qos_id in cls.qos_specs:
- test_utils.call_and_ignore_notfound_exc(
- cls.admin_volume_qos_client.delete_qos, qos_id)
+ def clear_qos_spec(cls, qos_id):
+ test_utils.call_and_ignore_notfound_exc(
+ cls.admin_volume_qos_client.delete_qos, qos_id)
- for qos_id in cls.qos_specs:
- test_utils.call_and_ignore_notfound_exc(
- cls.admin_volume_qos_client.wait_for_resource_deletion, qos_id)
+ test_utils.call_and_ignore_notfound_exc(
+ cls.admin_volume_qos_client.wait_for_resource_deletion, qos_id)
@classmethod
- def clear_volume_types(cls):
- for vol_type in cls.volume_types:
- test_utils.call_and_ignore_notfound_exc(
- cls.admin_volume_types_client.delete_volume_type, vol_type)
+ def clear_volume_type(cls, vol_type_id):
+ test_utils.call_and_ignore_notfound_exc(
+ cls.admin_volume_types_client.delete_volume_type, vol_type_id)
- for vol_type in cls.volume_types:
- test_utils.call_and_ignore_notfound_exc(
- cls.admin_volume_types_client.wait_for_resource_deletion,
- vol_type)
+ test_utils.call_and_ignore_notfound_exc(
+ cls.admin_volume_types_client.wait_for_resource_deletion,
+ vol_type_id)
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 1e240b8..552b231 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -40,7 +40,7 @@
backup_id)['restore']
# Delete backup
- self.addCleanup(self.volumes_client.delete_volume,
+ self.addCleanup(self.delete_volume, self.volumes_client,
restored_volume['volume_id'])
self.assertEqual(backup_id, restored_volume['backup_id'])
waiters.wait_for_volume_resource_status(self.backups_client,
@@ -59,8 +59,7 @@
"vol-meta2": "value2",
"vol-meta3": "value3"}
volume = self.create_volume(metadata=metadata)
- self.addCleanup(self.volumes_client.delete_volume,
- volume['id'])
+ self.addCleanup(self.delete_volume, self.volumes_client, volume['id'])
# Create a backup
backup_name = data_utils.rand_name(
@@ -109,8 +108,7 @@
"""
# Create a server
volume = self.create_volume()
- self.addCleanup(self.volumes_client.delete_volume,
- volume['id'])
+ self.addCleanup(self.delete_volume, self.volumes_client, volume['id'])
server = self.create_server()
# Attach volume to instance
self.attach_volume(server['id'], volume['id'])
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index b73bdf2..54052ae 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -80,11 +80,6 @@
# is implicit - Cinder calls Nova at that microversion, Tempest does not.
min_microversion = '3.42'
- @classmethod
- def setup_clients(cls):
- super(VolumesExtendAttachedTest, cls).setup_clients()
- cls.admin_servers_client = cls.os_admin.servers_client
-
def _find_extend_volume_instance_action(self, server_id):
actions = self.servers_client.list_instance_actions(
server_id)['instanceActions']
@@ -95,7 +90,7 @@
def _find_extend_volume_instance_action_finish_event(self, action):
# This has to be called by an admin client otherwise
# the events don't show up.
- action = self.admin_servers_client.show_instance_action(
+ action = self.os_admin.servers_client.show_instance_action(
action['instance_uuid'], action['request_id'])['instanceAction']
for event in action['events']:
if (event['event'] == 'compute_extend_volume' and
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 6294994..d5358ab 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -34,7 +34,20 @@
VOLUME_FIELDS = ('id', 'name')
- def assertVolumesIn(self, fetched_list, expected_list, fields=None):
+ @classmethod
+ def _remove_volatile_fields(cls, fetched_list):
+ """Remove fields that should not be compared.
+
+ This method makes sure that Tempest does not compare e.g.
+ the volume's "updated_at" field that may change for any reason
+ internal to the operation of Cinder.
+ """
+ for volume in fetched_list:
+ for field in ('updated_at',):
+ if field in volume:
+ del volume[field]
+
+ def _assert_volumes_in(self, fetched_list, expected_list, fields=None):
"""Check out the list.
This function is aim at check out whether all of the volumes in
@@ -45,6 +58,8 @@
expected_list = map(fieldsgetter, expected_list)
fetched_list = [fieldsgetter(item) for item in fetched_list]
+ # Hopefully the expected_list has already been cleaned.
+ self._remove_volatile_fields(fetched_list)
missing_vols = [v for v in expected_list if v not in fetched_list]
if not missing_vols:
return
@@ -72,6 +87,7 @@
volume = cls.volumes_client.show_volume(volume['id'])['volume']
cls.volume_list.append(volume)
cls.volume_id_list.append(volume['id'])
+ cls._remove_volatile_fields(cls.volume_list)
def _list_by_param_value_and_assert(self, params, with_detail=False):
"""list or list_details with given params and validates result"""
@@ -103,15 +119,15 @@
# Get a list of Volumes
# Fetch all volumes
fetched_list = self.volumes_client.list_volumes()['volumes']
- self.assertVolumesIn(fetched_list, self.volume_list,
- fields=self.VOLUME_FIELDS)
+ self._assert_volumes_in(fetched_list, self.volume_list,
+ fields=self.VOLUME_FIELDS)
@decorators.idempotent_id('adcbb5a7-5ad8-4b61-bd10-5380e111a877')
def test_volume_list_with_details(self):
# Get a list of Volumes with details
# Fetch all Volumes
fetched_list = self.volumes_client.list_volumes(detail=True)['volumes']
- self.assertVolumesIn(fetched_list, self.volume_list)
+ self._assert_volumes_in(fetched_list, self.volume_list)
@decorators.idempotent_id('a28e8da4-0b56-472f-87a8-0f4d3f819c02')
def test_volume_list_by_name(self):
@@ -137,8 +153,8 @@
fetched_list = self.volumes_client.list_volumes(
params=params)['volumes']
self._list_by_param_value_and_assert(params)
- self.assertVolumesIn(fetched_list, self.volume_list,
- fields=self.VOLUME_FIELDS)
+ self._assert_volumes_in(fetched_list, self.volume_list,
+ fields=self.VOLUME_FIELDS)
@decorators.idempotent_id('2943f712-71ec-482a-bf49-d5ca06216b9f')
def test_volumes_list_details_by_status(self):
@@ -147,7 +163,7 @@
detail=True, params=params)['volumes']
for volume in fetched_list:
self.assertEqual('available', volume['status'])
- self.assertVolumesIn(fetched_list, self.volume_list)
+ self._assert_volumes_in(fetched_list, self.volume_list)
@decorators.idempotent_id('2016a942-3020-40d7-95ce-7613bf8407ce')
def test_volumes_list_by_bootable(self):
@@ -160,8 +176,8 @@
fetched_list = self.volumes_client.list_volumes(
params=params)['volumes']
self._list_by_param_value_and_assert(params)
- self.assertVolumesIn(fetched_list, self.volume_list,
- fields=self.VOLUME_FIELDS)
+ self._assert_volumes_in(fetched_list, self.volume_list,
+ fields=self.VOLUME_FIELDS)
@decorators.idempotent_id('2016a939-72ec-482a-bf49-d5ca06216b9f')
def test_volumes_list_details_by_bootable(self):
@@ -170,7 +186,7 @@
detail=True, params=params)['volumes']
for volume in fetched_list:
self.assertEqual('false', volume['bootable'])
- self.assertVolumesIn(fetched_list, self.volume_list)
+ self._assert_volumes_in(fetched_list, self.volume_list)
@decorators.idempotent_id('c0cfa863-3020-40d7-b587-e35f597d5d87')
def test_volumes_list_by_availability_zone(self):
@@ -180,8 +196,8 @@
fetched_list = self.volumes_client.list_volumes(
params=params)['volumes']
self._list_by_param_value_and_assert(params)
- self.assertVolumesIn(fetched_list, self.volume_list,
- fields=self.VOLUME_FIELDS)
+ self._assert_volumes_in(fetched_list, self.volume_list,
+ fields=self.VOLUME_FIELDS)
@decorators.idempotent_id('e1b80d13-94f0-4ba2-a40e-386af29f8db1')
def test_volumes_list_details_by_availability_zone(self):
@@ -192,7 +208,7 @@
detail=True, params=params)['volumes']
for volume in fetched_list:
self.assertEqual(zone, volume['availability_zone'])
- self.assertVolumesIn(fetched_list, self.volume_list)
+ self._assert_volumes_in(fetched_list, self.volume_list)
@decorators.idempotent_id('b5ebea1b-0603-40a0-bb41-15fcd0a53214')
def test_volume_list_with_param_metadata(self):
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index 92eae02..1c671ec 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -162,9 +162,7 @@
if CONF.service_available.swift:
spec.append([CONF.object_storage.operator_role])
spec.append([CONF.object_storage.reseller_admin_role])
- if CONF.service_available.heat:
- spec.append([CONF.orchestration.stack_owner_role,
- CONF.object_storage.operator_role])
+ spec.append([CONF.object_storage.operator_role])
if admin:
spec.append('admin')
resources = []
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index d1e80f1..025959a 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -37,7 +37,6 @@
IS_CINDER = None
IS_GLANCE = None
-IS_HEAT = None
IS_NEUTRON = None
IS_NOVA = None
@@ -60,7 +59,6 @@
IS_CINDER = CONF.service_available.cinder
IS_GLANCE = CONF.service_available.glance
- IS_HEAT = CONF.service_available.heat
IS_NEUTRON = CONF.service_available.neutron
IS_NOVA = CONF.service_available.nova
@@ -212,33 +210,6 @@
self.data['server_groups'] = sgs
-class StackService(BaseService):
- def __init__(self, manager, **kwargs):
- super(StackService, self).__init__(kwargs)
- params = config.service_client_config('orchestration')
- self.client = manager.orchestration.OrchestrationClient(
- manager.auth_provider, **params)
-
- def list(self):
- client = self.client
- stacks = client.list_stacks()['stacks']
- LOG.debug("List count, %s Stacks", len(stacks))
- return stacks
-
- def delete(self):
- client = self.client
- stacks = self.list()
- for stack in stacks:
- try:
- client.delete_stack(stack['id'])
- except Exception:
- LOG.exception("Delete Stack exception.")
-
- def dry_run(self):
- stacks = self.list()
- self.data['stacks'] = stacks
-
-
class KeyPairService(BaseService):
def __init__(self, manager, **kwargs):
super(KeyPairService, self).__init__(kwargs)
@@ -960,8 +931,6 @@
if not IS_NEUTRON:
project_services.append(FloatingIpService)
project_services.append(NovaQuotaService)
- if IS_HEAT:
- project_services.append(StackService)
if IS_NEUTRON:
project_services.append(NetworkFloatingIpService)
if utils.is_extension_enabled('metering', 'network'):
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index fdf28d5..15af271 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -349,7 +349,6 @@
'image': 'glance',
'object_storage': 'swift',
'compute': 'nova',
- 'orchestration': 'heat',
'baremetal': 'ironic',
'identity': 'keystone',
}
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
index da34975..75db155 100644
--- a/tempest/common/credentials_factory.py
+++ b/tempest/common/credentials_factory.py
@@ -86,7 +86,7 @@
('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),
+ ('resource_prefix', 'tempest'),
('identity_admin_endpoint_type', endpoint_type)
]))
diff --git a/tempest/common/utils/__init__.py b/tempest/common/utils/__init__.py
index aa81864..225a713 100644
--- a/tempest/common/utils/__init__.py
+++ b/tempest/common/utils/__init__.py
@@ -31,10 +31,9 @@
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
+ # includes a random number and a prefix 'tempest'
attr_obj = partial(lib_data_utils.rand_name,
- prefix=CONF.resources_prefix)
+ prefix='tempest')
else:
attr_obj = getattr(lib_data_utils, attr)
diff --git a/tempest/config.py b/tempest/config.py
index fc95df8..231d005 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -65,9 +65,7 @@
deprecated_opts=[cfg.DeprecatedOpt('allow_tenant_isolation',
group='auth'),
cfg.DeprecatedOpt('allow_tenant_isolation',
- group='compute'),
- cfg.DeprecatedOpt('allow_tenant_isolation',
- group='orchestration')]),
+ group='compute')]),
cfg.ListOpt('tempest_roles',
help="Roles to assign to all users created by tempest",
default=[]),
@@ -541,13 +539,6 @@
'are current one. In future, Tempest will '
'test v2 APIs only so this config option '
'will be removed.'),
- cfg.BoolOpt('deactivate_image',
- default=False,
- help="Is the deactivate-image feature enabled."
- " The feature has been integrated since Kilo.",
- deprecated_for_removal=True,
- deprecated_reason="All supported versions of OpenStack now "
- "support the 'deactivate_image' feature"),
]
network_group = cfg.OptGroup(name='network',
@@ -916,66 +907,6 @@
help="Execute discoverability tests"),
]
-orchestration_group = cfg.OptGroup(name='orchestration',
- title='Orchestration Service Options')
-
-OrchestrationGroup = [
- cfg.StrOpt('catalog_type',
- default='orchestration',
- help="Catalog type of the Orchestration service.",
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
- cfg.StrOpt('region',
- default='',
- help="The orchestration 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.",
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
- cfg.StrOpt('endpoint_type',
- default='publicURL',
- choices=['public', 'admin', 'internal',
- 'publicURL', 'adminURL', 'internalURL'],
- help="The endpoint type to use for the orchestration service.",
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
- cfg.StrOpt('stack_owner_role', default='heat_stack_owner',
- help='Role required for users to be able to manage stacks',
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
- cfg.IntOpt('build_interval',
- default=1,
- help="Time in seconds between build status checks.",
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
- cfg.IntOpt('build_timeout',
- default=1200,
- help="Timeout in seconds to wait for a stack to build.",
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
- cfg.StrOpt('instance_type',
- default='m1.micro',
- help="Instance type for tests. Needs to be big enough for a "
- "full OS plus the test workload",
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
- cfg.StrOpt('keypair_name',
- help="Name of existing keypair to launch servers with.",
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
- cfg.IntOpt('max_template_size',
- default=524288,
- help="Value must match heat configuration of the same name.",
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
- cfg.IntOpt('max_resources_per_stack',
- default=1000,
- help="Value must match heat configuration of the same name.",
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
-]
-
scenario_group = cfg.OptGroup(name='scenario', title='Scenario Test Options')
@@ -1037,11 +968,6 @@
cfg.BoolOpt('nova',
default=True,
help="Whether or not nova is expected to be available"),
- cfg.BoolOpt('heat',
- default=False,
- help="Whether or not Heat is expected to be available",
- deprecated_for_removal=True,
- deprecated_reason='Heat support will be removed from Tempest'),
]
debug_group = cfg.OptGroup(name="debug",
@@ -1071,17 +997,6 @@
]
DefaultGroup = [
- cfg.StrOpt('resources_prefix',
- default='tempest',
- help="Prefix to be added when generating the name for "
- "test resources. It can be used to discover all "
- "resources associated with a specific test run when "
- "running tempest on a real-life cloud",
- deprecated_for_removal=True,
- deprecated_reason="It is enough to add 'tempest' as this "
- "prefix to ideintify resources which are "
- "created by Tempest and no projects set "
- "this option on OpenStack dev community."),
cfg.BoolOpt('pause_teardown',
default=False,
help="""Whether to pause a test in global teardown.
@@ -1109,7 +1024,6 @@
(volume_feature_group, VolumeFeaturesGroup),
(object_storage_group, ObjectStoreGroup),
(object_storage_feature_group, ObjectStoreFeaturesGroup),
- (orchestration_group, OrchestrationGroup),
(scenario_group, ScenarioGroup),
(service_available_group, ServiceAvailableGroup),
(debug_group, DebugGroup),
@@ -1176,7 +1090,6 @@
self.object_storage = _CONF['object-storage']
self.object_storage_feature_enabled = _CONF[
'object-storage-feature-enabled']
- self.orchestration = _CONF.orchestration
self.scenario = _CONF.scenario
self.service_available = _CONF.service_available
self.debug = _CONF.debug
diff --git a/tempest/lib/api_schema/response/compute/v2_45/__init__.py b/tempest/lib/api_schema/response/compute/v2_45/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_45/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_45/images.py b/tempest/lib/api_schema/response/compute/v2_45/images.py
new file mode 100644
index 0000000..8a48f36
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_45/images.py
@@ -0,0 +1,32 @@
+# 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.
+
+# The 2.45 microversion removes the "location" header and adds "image_id"
+# to the response body.
+create_image = {
+ 'status_code': [202],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'image_id': {'type': 'string'}
+ },
+ 'additionalProperties': False,
+ 'required': ['image_id']
+ }
+}
+
+# NOTE(mriedem): The compute proxy APIs for showing/listing and deleting
+# images were deprecated in microversion 2.35, and the compute proxy APIs for
+# working with image metadata were deprecated in microversion 2.39. Therefore,
+# client-side code shouldn't rely on those APIs in the compute images client
+# past those microversions and should instead use the Glance images client
+# directly.
diff --git a/tempest/lib/cli/base.py b/tempest/lib/cli/base.py
index f39ecbc..3a97801 100644
--- a/tempest/lib/cli/base.py
+++ b/tempest/lib/cli/base.py
@@ -101,12 +101,15 @@
:type project_domain_name: string
:param project_domain_id: Project's domain ID
:type project_domain_id: string
+ :param identity_api_version: Version of the Identity API
+ :type identity_api_version: string
"""
def __init__(self, username='', password='', tenant_name='', uri='',
cli_dir='', insecure=False, prefix='', user_domain_name=None,
user_domain_id=None, project_domain_name=None,
- project_domain_id=None, *args, **kwargs):
+ project_domain_id=None, identity_api_version=None, *args,
+ **kwargs):
"""Initialize a new CLIClient object."""
super(CLIClient, self).__init__()
self.cli_dir = cli_dir if cli_dir else '/usr/bin'
@@ -120,6 +123,7 @@
self.user_domain_id = user_domain_id
self.project_domain_name = project_domain_name
self.project_domain_id = project_domain_id
+ self.identity_api_version = identity_api_version
def nova(self, action, flags='', params='', fail_ok=False,
endpoint_type='publicURL', merge_stderr=False):
@@ -374,12 +378,15 @@
:param merge_stderr: if True the stderr buffer is merged into stdout
:type merge_stderr: boolean
"""
- creds = ('--os-username %s --os-tenant-name %s --os-password %s '
+ creds = ('--os-username %s --os-project-name %s --os-password %s '
'--os-auth-url %s' %
(self.username,
self.tenant_name,
self.password,
self.uri))
+ if self.identity_api_version:
+ creds += ' --os-identity-api-version %s' % (
+ self.identity_api_version)
if self.user_domain_name is not None:
creds += ' --os-user-domain-name %s' % self.user_domain_name
if self.user_domain_id is not None:
diff --git a/tempest/lib/common/fixed_network.py b/tempest/lib/common/fixed_network.py
index e2054a4..875a79d 100644
--- a/tempest/lib/common/fixed_network.py
+++ b/tempest/lib/common/fixed_network.py
@@ -38,7 +38,12 @@
raise exceptions.InvalidTestResource(type='network', name=name)
networks = compute_networks_client.list_networks()['networks']
- networks = [n for n in networks if n['label'] == name]
+ # NOTE(zhufl) compute networks_client uses 'label' as network name field,
+ # while neutron networks_client uses 'name' as network name field.
+ try:
+ networks = [n for n in networks if n['label'] == name]
+ except KeyError:
+ networks = [n for n in networks if n['name'] == name]
# Check that a network exists, else raise an InvalidConfigurationException
if len(networks) == 1:
diff --git a/tempest/lib/common/preprov_creds.py b/tempest/lib/common/preprov_creds.py
index 83db513..fcdeb17 100644
--- a/tempest/lib/common/preprov_creds.py
+++ b/tempest/lib/common/preprov_creds.py
@@ -344,11 +344,11 @@
net_creds = cred_provider.TestResources(credential)
net_clients = clients.ServiceClients(credentials=credential,
identity_uri=self.identity_uri)
- compute_network_client = net_clients.compute.NetworksClient()
+ networks_client = net_clients.network.NetworksClient()
net_name = self.hash_dict['networks'].get(hash, None)
try:
network = fixed_network.get_network_from_name(
- net_name, compute_network_client)
+ net_name, networks_client)
except lib_exc.InvalidTestResource:
network = {}
net_creds.set_resources(network=network)
diff --git a/tempest/lib/common/utils/linux/remote_client.py b/tempest/lib/common/utils/linux/remote_client.py
index 1676a28..94fab00 100644
--- a/tempest/lib/common/utils/linux/remote_client.py
+++ b/tempest/lib/common/utils/linux/remote_client.py
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import functools
import sys
import netaddr
@@ -25,6 +26,7 @@
def debug_ssh(function):
"""Decorator to generate extra debug info in case off SSH failure"""
+ @functools.wraps(function)
def wrapper(self, *args, **kwargs):
try:
return function(self, *args, **kwargs)
diff --git a/tempest/lib/common/utils/test_utils.py b/tempest/lib/common/utils/test_utils.py
index c2e93ee..2a9f3a9 100644
--- a/tempest/lib/common/utils/test_utils.py
+++ b/tempest/lib/common/utils/test_utils.py
@@ -102,13 +102,13 @@
now = time.time()
begin_time = now
timeout = now + duration
+ func_name = getattr(func, '__name__', getattr(func.__class__, '__name__'))
while now < timeout:
if func(*args, **kwargs):
LOG.debug("Call %s returns true in %f seconds",
- getattr(func, '__name__'), time.time() - begin_time)
+ func_name, time.time() - begin_time)
return True
time.sleep(sleep_for)
now = time.time()
- LOG.debug("Call %s returns false in %f seconds",
- getattr(func, '__name__'), duration)
+ LOG.debug("Call %s returns false in %f seconds", func_name, duration)
return False
diff --git a/tempest/lib/services/compute/images_client.py b/tempest/lib/services/compute/images_client.py
index 86bea9e..0f4eb42 100644
--- a/tempest/lib/services/compute/images_client.py
+++ b/tempest/lib/services/compute/images_client.py
@@ -17,6 +17,7 @@
from six.moves.urllib import parse as urllib
from tempest.lib.api_schema.response.compute.v2_1 import images as schema
+from tempest.lib.api_schema.response.compute.v2_45 import images as schemav245
from tempest.lib.common import rest_client
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import base_compute_client
@@ -24,6 +25,10 @@
class ImagesClient(base_compute_client.BaseComputeClient):
+ schema_versions_info = [
+ {'min': None, 'max': '2.44', 'schema': schema},
+ {'min': '2.45', 'max': None, 'schema': schemav245}]
+
def create_image(self, server_id, **kwargs):
"""Create an image of the original server.
@@ -36,7 +41,10 @@
post_body = json.dumps(post_body)
resp, body = self.post('servers/%s/action' % server_id,
post_body)
- self.validate_response(schema.create_image, resp, body)
+ _schema = self.get_schema(self.schema_versions_info)
+ if body:
+ body = json.loads(body)
+ self.validate_response(_schema.create_image, resp, body)
return rest_client.ResponseBody(resp, body)
def list_images(self, detail=False, **params):
diff --git a/tempest/lib/services/compute/quota_classes_client.py b/tempest/lib/services/compute/quota_classes_client.py
index 0fe9868..64e06f4 100644
--- a/tempest/lib/services/compute/quota_classes_client.py
+++ b/tempest/lib/services/compute/quota_classes_client.py
@@ -35,8 +35,9 @@
def update_quota_class_set(self, quota_class_id, **kwargs):
"""Update the quota class's limits for one or more resources.
- # NOTE: Current api-site doesn't contain this API description.
- # LP: https://bugs.launchpad.net/nova/+bug/1602400
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/compute/#create-or-update-quotas-for-quota-class
"""
post_body = json.dumps({'quota_class_set': kwargs})
diff --git a/tempest/lib/services/compute/quotas_client.py b/tempest/lib/services/compute/quotas_client.py
index daf4bc0..12df895 100644
--- a/tempest/lib/services/compute/quotas_client.py
+++ b/tempest/lib/services/compute/quotas_client.py
@@ -28,8 +28,8 @@
For a full list of available parameters, please refer to the official
API reference:
- http://developer.openstack.org/api-ref-compute-v2.1.html/#show-a-quota
- http://developer.openstack.org/api-ref-compute-v2.1.html/#show-the-detail-of-quota
+ https://developer.openstack.org/api-ref/compute/#show-a-quota
+ https://developer.openstack.org/api-ref/compute/#show-the-detail-of-quota
"""
params = {}
@@ -49,7 +49,10 @@
return rest_client.ResponseBody(resp, body)
def show_default_quota_set(self, tenant_id):
- """List the default quota set for a tenant."""
+ """List the default quota set for a tenant.
+
+ https://developer.openstack.org/api-ref/compute/#list-default-quotas-for-tenant
+ """
url = 'os-quota-sets/%s/defaults' % tenant_id
resp, body = self.get(url)
@@ -79,7 +82,10 @@
return rest_client.ResponseBody(resp, body)
def delete_quota_set(self, tenant_id):
- """Delete the tenant's quota set."""
+ """Delete the tenant's quota set.
+
+ https://developer.openstack.org/api-ref/compute/#revert-quotas-to-defaults
+ """
resp, body = self.delete('os-quota-sets/%s' % tenant_id)
self.validate_response(schema.delete_quota, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index 598d5a6..09bccab 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -126,7 +126,7 @@
For a full list of available parameters, please refer to the official
API reference:
- http://developer.openstack.org/api-ref-compute-v2.1.html#showServer
+ https://developer.openstack.org/api-ref/compute/#show-server-details
"""
resp, body = self.get("servers/%s" % server_id)
body = json.loads(body)
@@ -321,7 +321,7 @@
For a full list of available parameters, please refer to the official
API reference:
- https://developer.openstack.org/api-ref/compute/#create-or-replace-metadata-items
+ https://developer.openstack.org/api-ref/compute/#replace-metadata-items
"""
if no_metadata_field:
post_body = ""
@@ -338,7 +338,7 @@
For a full list of available parameters, please refer to the official
API reference:
- https://developer.openstack.org/api-ref/compute/#update-metadata-items
+ https://developer.openstack.org/api-ref/compute/#create-or-update-metadata-items
"""
post_body = json.dumps({'metadata': meta})
resp, body = self.post('servers/%s/metadata' % server_id,
@@ -609,9 +609,7 @@
For a full list of available parameters, please refer to the official
API reference:
- TODO (markus_z) The api-ref for that isn't yet available, update this
- here when the docs in Nova are updated. The old API is at
- http://developer.openstack.org/api-ref/compute/#get-serial-console-os-getserialconsole-action
+ https://developer.openstack.org/api-ref/compute/#create-remote-console
"""
param = {
'remote_console': {
@@ -722,7 +720,7 @@
For a full list of available parameters, please refer to the official
API reference:
- https://developer.openstack.org/api-ref/compute/#get-vnc-console-os-getvncconsole-action
+ https://developer.openstack.org/api-ref/compute/#get-vnc-console-os-getvncconsole-action-deprecated
"""
return self.action(server_id, "os-getVNCConsole",
schema.get_vnc_console, **kwargs)
@@ -732,7 +730,7 @@
For a full list of available parameters, please refer to the official
API reference:
- https://developer.openstack.org/api-ref/compute/#add-associate-fixed-ip-addfixedip-action
+ https://developer.openstack.org/api-ref/compute/#add-associate-fixed-ip-addfixedip-action-deprecated
"""
return self.action(server_id, 'addFixedIp', **kwargs)
@@ -741,7 +739,7 @@
For a full list of available parameters, please refer to the official
API reference:
- https://developer.openstack.org/api-ref/compute/#remove-disassociate-fixed-ip-removefixedip-action
+ https://developer.openstack.org/api-ref/compute/#remove-disassociate-fixed-ip-removefixedip-action-deprecated
"""
return self.action(server_id, 'removeFixedIp', **kwargs)
diff --git a/tempest/lib/services/network/quotas_client.py b/tempest/lib/services/network/quotas_client.py
index fdd3d6b..f23af88 100644
--- a/tempest/lib/services/network/quotas_client.py
+++ b/tempest/lib/services/network/quotas_client.py
@@ -41,3 +41,8 @@
def list_quotas(self, **filters):
uri = '/quotas'
return self.list_resources(uri, **filters)
+
+ def show_default_quotas(self, tenant_id):
+ """List default quotas for a project."""
+ uri = '/quotas/%s/default' % tenant_id
+ return self.show_resource(uri)
diff --git a/tempest/lib/services/volume/v2/quota_classes_client.py b/tempest/lib/services/volume/v2/quota_classes_client.py
index d40d2d9..733b1ac 100644
--- a/tempest/lib/services/volume/v2/quota_classes_client.py
+++ b/tempest/lib/services/volume/v2/quota_classes_client.py
@@ -26,8 +26,9 @@
def show_quota_class_set(self, quota_class_id):
"""List quotas for a quota class.
- TODO: Current api-site doesn't contain this API description.
- LP: https://bugs.launchpad.net/nova/+bug/1602400
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v2/index.html#show-quota-classes
"""
url = 'os-quota-class-sets/%s' % quota_class_id
resp, body = self.get(url)
@@ -38,8 +39,9 @@
def update_quota_class_set(self, quota_class_id, **kwargs):
"""Update quotas for a quota class.
- TODO: Current api-site doesn't contain this API description.
- LP: https://bugs.launchpad.net/nova/+bug/1602400
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v2/index.html#update-quota-classes
"""
url = 'os-quota-class-sets/%s' % quota_class_id
put_body = json.dumps({'quota_class_set': kwargs})
diff --git a/tempest/lib/services/volume/v3/group_types_client.py b/tempest/lib/services/volume/v3/group_types_client.py
index 6181472..1b47201 100644
--- a/tempest/lib/services/volume/v3/group_types_client.py
+++ b/tempest/lib/services/volume/v3/group_types_client.py
@@ -88,3 +88,54 @@
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
+
+ def create_or_update_group_type_specs(self, group_type_id, group_specs):
+ """Creates new group specs or updates existing group specs.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v3/#create-group-specs-for-a-group-type
+ """
+ url = "group_types/%s/group_specs" % group_type_id
+ post_body = json.dumps({'group_specs': group_specs})
+ resp, body = self.post(url, post_body)
+ body = json.loads(body)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_group_type_specs(self, group_type_id):
+ """Lists all group specs for a given group type."""
+ url = 'group_types/%s/group_specs' % group_type_id
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def show_group_type_specs_item(self, group_type_id, spec_id):
+ """Shows specified item of group specs for a given group type."""
+ url = "group_types/%s/group_specs/%s" % (group_type_id, spec_id)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def update_group_type_specs_item(self, group_type_id, spec_id, spec):
+ """Updates specified item of group specs for a given group type.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v3/#update-one-specific-group-spec-for-a-group-type
+ """
+ url = "group_types/%s/group_specs/%s" % (group_type_id, spec_id)
+ put_body = json.dumps(spec)
+ resp, body = self.put(url, put_body)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_group_type_specs_item(self, group_type_id, spec_id):
+ """Deletes specified item of group specs for a given group type."""
+ resp, body = self.delete("group_types/%s/group_specs/%s" % (
+ group_type_id, spec_id))
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 29f1743..0df26ea 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.common import custom_matchers
from tempest.common import utils
from tempest.common import waiters
@@ -101,10 +99,6 @@
return address
@decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
- @testtools.skipUnless(CONF.network.public_network_id,
- 'The public_network_id option must be specified.')
- @testtools.skipUnless(CONF.network_feature_enabled.floating_ips,
- 'Floating ips are not available')
@utils.services('compute', 'volume', 'image', 'network')
def test_minimum_basic_scenario(self):
image = self.glance_image_create()
@@ -126,22 +120,28 @@
self.addCleanup(self.nova_volume_detach, server, volume)
self.cinder_show(volume)
- floating_ip = self.create_floating_ip(server)
- # fetch the server again to make sure the addresses were refreshed
- # after associating the floating IP
+ floating_ip = None
server = self.servers_client.show_server(server['id'])['server']
- address = self._get_floating_ip_in_server_addresses(
- floating_ip, server)
- self.assertIsNotNone(
- address,
- "Failed to find floating IP '%s' in server addresses: %s" %
- (floating_ip['ip'], server['addresses']))
+ if (CONF.network_feature_enabled.floating_ips and
+ CONF.network.floating_network_name):
+ floating_ip = self.create_floating_ip(server)
+ # fetch the server again to make sure the addresses were refreshed
+ # after associating the floating IP
+ address = self._get_floating_ip_in_server_addresses(
+ floating_ip, server)
+ self.assertIsNotNone(
+ address,
+ "Failed to find floating IP '%s' in server addresses: %s" %
+ (floating_ip['ip'], server['addresses']))
+ ssh_ip = floating_ip['ip']
+ else:
+ ssh_ip = self.get_server_ip(server)
self.create_and_add_security_group_to_server(server)
# check that we can SSH to the server before reboot
self.linux_client = self.get_remote_client(
- floating_ip['ip'], private_key=keypair['private_key'],
+ ssh_ip, private_key=keypair['private_key'],
server=server)
self.nova_reboot(server)
@@ -149,25 +149,27 @@
# check that we can SSH to the server after reboot
# (both connections are part of the scenario)
self.linux_client = self.get_remote_client(
- floating_ip['ip'], private_key=keypair['private_key'],
+ ssh_ip, private_key=keypair['private_key'],
server=server)
self.check_disks()
- # delete the floating IP, this should refresh the server addresses
- self.compute_floating_ips_client.delete_floating_ip(floating_ip['id'])
+ if floating_ip:
+ # delete the floating IP, this should refresh the server addresses
+ self.compute_floating_ips_client.delete_floating_ip(
+ floating_ip['id'])
- def is_floating_ip_detached_from_server():
- server_info = self.servers_client.show_server(
- server['id'])['server']
- address = self._get_floating_ip_in_server_addresses(
- floating_ip, server_info)
- return (not address)
+ def is_floating_ip_detached_from_server():
+ server_info = self.servers_client.show_server(
+ server['id'])['server']
+ address = self._get_floating_ip_in_server_addresses(
+ floating_ip, server_info)
+ return (not address)
- if not test_utils.call_until_true(
- is_floating_ip_detached_from_server,
- CONF.compute.build_timeout,
- CONF.compute.build_interval):
- msg = ("Floating IP '%s' should not be in server addresses: %s" %
- (floating_ip['ip'], server['addresses']))
- raise exceptions.TimeoutException(msg)
+ if not test_utils.call_until_true(
+ is_floating_ip_detached_from_server,
+ CONF.compute.build_timeout,
+ CONF.compute.build_interval):
+ msg = ("Floating IP '%s' should not be in server addresses: %s"
+ % (floating_ip['ip'], server['addresses']))
+ raise exceptions.TimeoutException(msg)
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index 7c404ad..e4ab11c 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -195,6 +195,8 @@
waiters.wait_for_server_status(self.servers_client, server['id'],
'VERIFY_RESIZE')
self.servers_client.confirm_resize_server(server['id'])
+ server = self.servers_client.show_server(server['id'])['server']
+ self.assertEqual(resize_flavor, server['flavor']['id'])
self._wait_server_status_and_check_network_connectivity(
server, keypair, floating_ip)
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index d5c378e..1be8625 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -43,12 +43,6 @@
* Terminate the instance
"""
- @classmethod
- def skip_checks(cls):
- super(TestServerBasicOps, cls).skip_checks()
- if not CONF.network_feature_enabled.floating_ips:
- raise cls.skipException("Floating ips are not available")
-
def setUp(self):
super(TestServerBasicOps, self).setUp()
self.run_ssh = CONF.validation.run_validation
@@ -56,11 +50,17 @@
def verify_ssh(self, keypair):
if self.run_ssh:
- # Obtain a floating IP
- self.fip = self.create_floating_ip(self.instance)['ip']
+ # Obtain a floating IP if floating_ips is enabled
+ if (CONF.network_feature_enabled.floating_ips and
+ CONF.network.floating_network_name):
+ self.ip = self.create_floating_ip(self.instance)['ip']
+ else:
+ server = self.servers_client.show_server(
+ self.instance['id'])['server']
+ self.ip = self.get_server_ip(server)
# Check ssh
self.ssh_client = self.get_remote_client(
- ip_address=self.fip,
+ ip_address=self.ip,
username=self.ssh_user,
private_key=keypair['private_key'],
server=self.instance)
@@ -75,8 +75,8 @@
result = self.ssh_client.exec_command(cmd)
if result:
msg = ('Failed while verifying metadata on server. Result '
- 'of command "%s" is NOT "%s".' % (cmd, self.fip))
- self.assertEqual(self.fip, result, msg)
+ 'of command "%s" is NOT "%s".' % (cmd, self.ip))
+ self.assertEqual(self.ip, result, msg)
return 'Verification is successful!'
if not test_utils.call_until_true(exec_cmd_and_verify_output,
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index cd10bbd..ff7996a 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -38,6 +38,11 @@
credentials = ['primary', 'admin']
@classmethod
+ def setup_clients(cls):
+ super(TestVolumeMigrateRetypeAttached, cls).setup_clients()
+ cls.admin_volumes_client = cls.os_admin.volumes_v2_client
+
+ @classmethod
def skip_checks(cls):
super(TestVolumeMigrateRetypeAttached, cls).skip_checks()
if not CONF.volume_feature_enabled.multi_backend:
@@ -76,8 +81,10 @@
return source_body['name'], dest_body['name']
def _volume_retype_with_migration(self, volume_id, new_volume_type):
+ # NOTE: The 'on-demand' migration requires admin operation, so
+ # admin_volumes_client() should be used here.
migration_policy = 'on-demand'
- self.volumes_client.retype_volume(
+ self.admin_volumes_client.retype_volume(
volume_id, new_type=new_volume_type,
migration_policy=migration_policy)
waiters.wait_for_volume_retype(self.volumes_client,
diff --git a/tempest/test.py b/tempest/test.py
index 9da85d5..27e0165 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -836,7 +836,7 @@
manager = cls.get_client_manager()
# Make sure cred_provider exists and get a network client
- networks_client = manager.compute_networks_client
+ networks_client = manager.networks_client
cred_provider = cls._get_credentials_provider()
# In case of nova network, isolated tenants are not able to list the
# network configured in fixed_network_name, even if they can use it
diff --git a/tempest/tests/cmd/test_account_generator.py b/tempest/tests/cmd/test_account_generator.py
index 8bf4c5b..fd9af08 100644
--- a/tempest/tests/cmd/test_account_generator.py
+++ b/tempest/tests/cmd/test_account_generator.py
@@ -153,17 +153,14 @@
def test_generate_resources_no_admin(self):
cfg.CONF.set_default('swift', False, group='service_available')
- cfg.CONF.set_default('heat', False, group='service_available')
cfg.CONF.set_default('operator_role', 'fake_operator',
group='object-storage')
cfg.CONF.set_default('reseller_admin_role', 'fake_reseller',
group='object-storage')
- cfg.CONF.set_default('stack_owner_role', 'fake_owner',
- group='orchestration')
resources = account_generator.generate_resources(
self.cred_provider, admin=False)
resource_types = [k for k, _ in resources]
- # No admin, no heat, no swift, expect two credentials only
+ # No admin, no swift, expect two credentials only
self.assertEqual(2, len(resources))
# Ensure create_user was invoked twice (two distinct users)
self.assertEqual(2, self.user_create_fixture.mock.call_count)
@@ -180,17 +177,14 @@
def test_generate_resources_admin(self):
cfg.CONF.set_default('swift', False, group='service_available')
- cfg.CONF.set_default('heat', False, group='service_available')
cfg.CONF.set_default('operator_role', 'fake_operator',
group='object-storage')
cfg.CONF.set_default('reseller_admin_role', 'fake_reseller',
group='object-storage')
- cfg.CONF.set_default('stack_owner_role', 'fake_owner',
- group='orchestration')
resources = account_generator.generate_resources(
self.cred_provider, admin=True)
resource_types = [k for k, _ in resources]
- # Admin, no heat, no swift, expect three credentials only
+ # Admin, no swift, expect three credentials only
self.assertEqual(3, len(resources))
# Ensure create_user was invoked 3 times (3 distinct users)
self.assertEqual(3, self.user_create_fixture.mock.call_count)
@@ -205,28 +199,24 @@
self.assertIsNotNone(resource[1].router)
self.assertIsNotNone(resource[1].subnet)
- def test_generate_resources_swift_heat_admin(self):
+ def test_generate_resources_swift_admin(self):
cfg.CONF.set_default('swift', True, group='service_available')
- cfg.CONF.set_default('heat', True, group='service_available')
cfg.CONF.set_default('operator_role', 'fake_operator',
group='object-storage')
cfg.CONF.set_default('reseller_admin_role', 'fake_reseller',
group='object-storage')
- cfg.CONF.set_default('stack_owner_role', 'fake_owner',
- group='orchestration')
resources = account_generator.generate_resources(
self.cred_provider, admin=True)
resource_types = [k for k, _ in resources]
# all options on, expect six credentials
self.assertEqual(6, len(resources))
# Ensure create_user was invoked 6 times (6 distinct users)
- self.assertEqual(6, self.user_create_fixture.mock.call_count)
+ self.assertEqual(5, self.user_create_fixture.mock.call_count)
self.assertIn('primary', resource_types)
self.assertIn('alt', resource_types)
self.assertIn('admin', resource_types)
self.assertIn(['fake_operator'], resource_types)
self.assertIn(['fake_reseller'], resource_types)
- self.assertIn(['fake_owner', 'fake_operator'], resource_types)
for resource in resources:
self.assertIsNotNone(resource[1].network)
self.assertIsNotNone(resource[1].router)
@@ -258,7 +248,6 @@
self.opts)
self.mock_resource_creation()
cfg.CONF.set_default('swift', True, group='service_available')
- cfg.CONF.set_default('heat', True, group='service_available')
self.resources = account_generator.generate_resources(
self.cred_provider, admin=True)
diff --git a/tempest/tests/fake_config.py b/tempest/tests/fake_config.py
index ee63684..4a2fff4 100644
--- a/tempest/tests/fake_config.py
+++ b/tempest/tests/fake_config.py
@@ -39,11 +39,12 @@
self.conf.set_default('uri_v3', 'http://fake_uri_v3.com/auth',
group='identity')
self.conf.set_default('neutron', True, group='service_available')
- self.conf.set_default('heat', True, group='service_available')
- if not os.path.exists(str(os.environ.get('OS_TEST_LOCK_PATH'))):
- os.mkdir(str(os.environ.get('OS_TEST_LOCK_PATH')))
+ lock_path = str(os.environ.get('OS_TEST_LOCK_PATH',
+ os.environ.get('TMPDIR', '/tmp')))
+ if not os.path.exists(lock_path):
+ os.mkdir(lock_path)
lockutils.set_defaults(
- lock_path=str(os.environ.get('OS_TEST_LOCK_PATH')),
+ lock_path=lock_path,
)
self.conf.set_default('auth_version', 'v2', group='identity')
for config_option in ['username', 'password', 'project_name']:
diff --git a/tempest/tests/lib/cli/test_execute.py b/tempest/tests/lib/cli/test_execute.py
index c276386..c069af5 100644
--- a/tempest/tests/lib/cli/test_execute.py
+++ b/tempest/tests/lib/cli/test_execute.py
@@ -125,3 +125,27 @@
mock_execute.call_args[0][2])
self.assertNotIn('--os-project-domain-name',
mock_execute.call_args[0][2])
+
+ @mock.patch.object(cli_base, 'execute')
+ def test_execute_with_default_api_version(self, mock_execute):
+ cli = cli_base.CLIClient()
+ cli.openstack('action')
+ self.assertEqual(mock_execute.call_count, 1)
+ self.assertNotIn('--os-identity-api-version ',
+ mock_execute.call_args[0][2])
+
+ @mock.patch.object(cli_base, 'execute')
+ def test_execute_with_empty_api_version(self, mock_execute):
+ cli = cli_base.CLIClient(identity_api_version='')
+ cli.openstack('action')
+ self.assertEqual(mock_execute.call_count, 1)
+ self.assertNotIn('--os-identity-api-version ',
+ mock_execute.call_args[0][2])
+
+ @mock.patch.object(cli_base, 'execute')
+ def test_execute_with_explicit_api_version(self, mock_execute):
+ cli = cli_base.CLIClient(identity_api_version='0.0')
+ cli.openstack('action')
+ self.assertEqual(mock_execute.call_count, 1)
+ self.assertIn('--os-identity-api-version 0.0 ',
+ mock_execute.call_args[0][2])
diff --git a/tempest/tests/lib/common/test_preprov_creds.py b/tempest/tests/lib/common/test_preprov_creds.py
index 9b10159..25df2a7 100644
--- a/tempest/tests/lib/common/test_preprov_creds.py
+++ b/tempest/tests/lib/common/test_preprov_creds.py
@@ -339,7 +339,7 @@
return_value=test_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
- with mock.patch('tempest.lib.services.compute.networks_client.'
+ with mock.patch('tempest.lib.services.network.networks_client.'
'NetworksClient.list_networks',
return_value={'networks': [{'name': 'network-2',
'id': 'fake-id',
diff --git a/tempest/tests/lib/services/network/test_quotas_client.py b/tempest/tests/lib/services/network/test_quotas_client.py
index e76bc9c..5a09911 100644
--- a/tempest/tests/lib/services/network/test_quotas_client.py
+++ b/tempest/tests/lib/services/network/test_quotas_client.py
@@ -38,6 +38,20 @@
]
}
+ FAKE_PROJECT_QUOTAS = {
+ "quota": {
+ "floatingip": 50,
+ "network": 10,
+ "port": 50,
+ "rbac_policy": -1,
+ "router": 10,
+ "security_group": 10,
+ "security_group_rule": 100,
+ "subnet": 10,
+ "subnetpool": -1
+ }
+ }
+
FAKE_QUOTA_TENANT_ID = "bab7d5c60cd041a0a36f7c4b6e1dd978"
def setUp(self):
@@ -58,7 +72,16 @@
self.check_service_client_function(
self.quotas_client.show_quotas,
"tempest.lib.common.rest_client.RestClient.get",
- {"quota": self.FAKE_QUOTAS["quotas"][0]},
+ self.FAKE_PROJECT_QUOTAS,
+ bytes_body,
+ 200,
+ tenant_id=self.FAKE_QUOTA_TENANT_ID)
+
+ def _test_show_default_quotas(self, bytes_body=False):
+ self.check_service_client_function(
+ self.quotas_client.show_default_quotas,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_PROJECT_QUOTAS,
bytes_body,
200,
tenant_id=self.FAKE_QUOTA_TENANT_ID)
@@ -67,7 +90,7 @@
self.check_service_client_function(
self.quotas_client.update_quotas,
"tempest.lib.common.rest_client.RestClient.put",
- {"quota": self.FAKE_QUOTAS["quotas"][0]},
+ self.FAKE_PROJECT_QUOTAS,
bytes_body,
200,
tenant_id=self.FAKE_QUOTA_TENANT_ID)
@@ -92,6 +115,12 @@
def test_show_quotas_with_bytes_body(self):
self._test_show_quotas(bytes_body=True)
+ def test_show_default_quotas_with_str_body(self):
+ self._test_show_default_quotas()
+
+ def test_show_default_quotas_with_bytes_body(self):
+ self._test_show_default_quotas(bytes_body=True)
+
def test_update_quotas_with_str_body(self):
self._test_update_quotas()
diff --git a/tempest/tests/lib/services/volume/v3/test_group_types_client.py b/tempest/tests/lib/services/volume/v3/test_group_types_client.py
index e86594e..c60cc36 100644
--- a/tempest/tests/lib/services/volume/v3/test_group_types_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_group_types_client.py
@@ -69,6 +69,28 @@
]
}
+ FAKE_CREATE_GROUP_TYPE_SPECS = {
+ "group_specs": {
+ "key1": "value1",
+ "key2": "value2"
+ }
+ }
+
+ FAKE_LIST_GROUP_TYPE_SPECS = {
+ "group_specs": {
+ "key1": "value1",
+ "key2": "value2"
+ }
+ }
+
+ FAKE_SHOW_GROUP_TYPE_SPECS_ITEM = {
+ "key1": "value1"
+ }
+
+ FAKE_UPDATE_GROUP_TYPE_SPECS_ITEM = {
+ "key2": "value2-updated"
+ }
+
def setUp(self):
super(TestGroupTypesClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -111,6 +133,45 @@
group_type_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5",
name='updated-group-type-name')
+ def _test_create_or_update_group_type_specs(self, bytes_body=False):
+ group_specs = self.FAKE_CREATE_GROUP_TYPE_SPECS['group_specs']
+ self.check_service_client_function(
+ self.client.create_or_update_group_type_specs,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_GROUP_TYPE_SPECS,
+ bytes_body,
+ group_type_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+ group_specs=group_specs,
+ status=202)
+
+ def _test_list_group_type_specs(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_group_type_specs,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_GROUP_TYPE_SPECS,
+ bytes_body,
+ group_type_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+
+ def _test_show_group_type_specs_item(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_group_type_specs_item,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SHOW_GROUP_TYPE_SPECS_ITEM,
+ bytes_body,
+ group_type_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+ spec_id="key1")
+
+ def _test_update_group_type_specs_item(self, bytes_body=False):
+ spec = self.FAKE_UPDATE_GROUP_TYPE_SPECS_ITEM
+ self.check_service_client_function(
+ self.client.update_group_type_specs_item,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATE_GROUP_TYPE_SPECS_ITEM,
+ bytes_body,
+ group_type_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+ spec_id="key2",
+ spec=spec)
+
def test_create_group_type_with_str_body(self):
self._test_create_group_type()
@@ -142,3 +203,36 @@
def test_update_group_types_with_bytes_body(self):
self._test_update_group_types(bytes_body=True)
+
+ def test_create_or_update_group_type_specs_with_str_body(self):
+ self._test_create_or_update_group_type_specs()
+
+ def test_create_or_update_group_type_specs_with_bytes_body(self):
+ self._test_create_or_update_group_type_specs(bytes_body=True)
+
+ def test_list_group_type_specs_with_str_body(self):
+ self._test_list_group_type_specs()
+
+ def test_list_group_type_specs_with_bytes_body(self):
+ self._test_list_group_type_specs(bytes_body=True)
+
+ def test_show_group_type_specs_item_with_str_body(self):
+ self._test_show_group_type_specs_item()
+
+ def test_show_group_type_specs_item_with_bytes_body(self):
+ self._test_show_group_type_specs_item(bytes_body=True)
+
+ def test_update_group_type_specs_item_with_str_body(self):
+ self._test_update_group_type_specs_item()
+
+ def test_update_group_type_specs_item_with_bytes_body(self):
+ self._test_update_group_type_specs_item(bytes_body=True)
+
+ def test_delete_group_type_specs_item(self):
+ self.check_service_client_function(
+ self.client.delete_group_type_specs_item,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ group_type_id='0e58433f-d108-4bf3-a22c-34e6b71ef86b',
+ spec_id='key1',
+ status=202)
diff --git a/tempest/tests/test_base_test.py b/tempest/tests/test_base_test.py
index 011bc9b..2b5a947 100644
--- a/tempest/tests/test_base_test.py
+++ b/tempest/tests/test_base_test.py
@@ -41,7 +41,7 @@
def test_get_tenant_network(self, mock_gtn, mock_gprov, mock_gcm):
net_client = mock.Mock()
mock_prov = mock.Mock()
- mock_gcm.return_value.compute_networks_client = net_client
+ mock_gcm.return_value.networks_client = net_client
mock_gprov.return_value = mock_prov
test.BaseTestCase.get_tenant_network()
@@ -85,7 +85,7 @@
mock_gcm):
net_client = mock.Mock()
mock_prov = mock.Mock()
- mock_gcm.return_value.compute_networks_client = net_client
+ mock_gcm.return_value.networks_client = net_client
mock_gprov.return_value = mock_prov
test.BaseTestCase.get_tenant_network(credentials_type='alt')
@@ -102,7 +102,7 @@
mock_gcm):
net_client = mock.Mock()
mock_prov = mock.Mock()
- mock_gcm.return_value.compute_networks_client = net_client
+ mock_gcm.return_value.networks_client = net_client
mock_gprov.return_value = mock_prov
creds = ['foo_type', 'role1']
diff --git a/test-requirements.txt b/test-requirements.txt
index 37644d0..e33f207 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -2,11 +2,7 @@
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
-# needed for doc build
-sphinx>=1.6.2 # BSD
-openstackdocstheme>=1.17.0 # Apache-2.0
-reno>=2.5.0 # Apache-2.0
mock>=2.0.0 # BSD
coverage!=4.4,>=4.0 # Apache-2.0
-oslotest>=1.10.0 # Apache-2.0
+oslotest>=3.2.0 # Apache-2.0
flake8-import-order==0.11 # LGPLv3
diff --git a/tox.ini b/tox.ini
index e7ea1e2..892b6f4 100644
--- a/tox.ini
+++ b/tox.ini
@@ -123,6 +123,10 @@
tempest run --serial --regex '\[.*\bsmoke\b.*\]' {posargs}
[testenv:venv]
+deps =
+ -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+ -r{toxinidir}/requirements.txt
+ -r{toxinidir}/doc/requirements.txt
commands = {posargs}
[testenv:venv-tempest]
@@ -133,9 +137,14 @@
commands = {posargs}
[testenv:docs]
+deps =
+ -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+ -r{toxinidir}/requirements.txt
+ -r{toxinidir}/doc/requirements.txt
commands =
- rm -rf doc/build
- python setup.py build_sphinx {posargs}
+ rm -rf doc/build
+ sphinx-build -b html doc/source doc/build/html
+whitelist_externals = rm
[testenv:pep8]
commands =
@@ -161,9 +170,15 @@
import-order-style = pep8
[testenv:releasenotes]
+deps =
+ -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+ -r{toxinidir}/requirements.txt
+ -r{toxinidir}/doc/requirements.txt
commands =
- rm -rf releasenotes/build
- sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
+ rm -rf releasenotes/build
+ sphinx-build -a -E -W -d releasenotes/build/doctrees \
+ -b html releasenotes/source releasenotes/build/html
+whitelist_externals = rm
[testenv:pip-check-reqs]
# Do not install test-requirements as that will pollute the virtualenv for