Merge "Add doc for supported OpenStack release & py version"
diff --git a/.zuul.yaml b/.zuul.yaml
index d893483..403c93d 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -100,6 +100,13 @@
devstack_localrc:
ENABLE_FILE_INJECTION: true
ENABLE_VOLUME_MULTIATTACH: true
+ devstack_services:
+ # NOTE(mriedem): Disable the cinder-backup service from tempest-full
+ # since tempest-full is in the integrated-gate project template but
+ # the backup tests do not really involve other services so they should
+ # be run in some more cinder-specific job, especially because the
+ # tests fail at a high rate (see bugs 1483434, 1813217, 1745168)
+ c-bak: false
- job:
name: tempest-full-oslo-master
@@ -169,6 +176,12 @@
s-object: false
s-proxy: false
# without Swift, c-bak cannot run (in the Gate at least)
+ # NOTE(mriedem): Disable the cinder-backup service from
+ # tempest-full-py3 since tempest-full-py3 is in the integrated-gate-py3
+ # project template but the backup tests do not really involve other
+ # services so they should be run in some more cinder-specific job,
+ # especially because the tests fail at a high rate (see bugs 1483434,
+ # 1813217, 1745168)
c-bak: false
- job:
@@ -339,14 +352,18 @@
vars:
devstack_localrc:
USE_PYTHON3: true
+ group-vars:
+ subnode:
+ devstack_localrc:
+ USE_PYTHON3: true
- job:
- name: tempest-full-py3-opensuse150
+ name: tempest-full-py3-opensuse15
parent: tempest-full-py3
- nodeset: devstack-single-node-opensuse-150
+ nodeset: devstack-single-node-opensuse-15
description: |
Base integration test with Neutron networking and py36 running
- on openSUSE Leap 15.0
+ on openSUSE Leap 15.x
voting: false
- job:
@@ -403,6 +420,20 @@
s-proxy: false
# without Swift, c-bak cannot run (in the Gate at least)
c-bak: false
+ group-vars:
+ subnode:
+ devstack_localrc:
+ USE_PYTHON3: true
+
+- job:
+ name: tempest-full-train
+ parent: tempest-full
+ override-checkout: stable/train
+
+- job:
+ name: tempest-full-train-py3
+ parent: tempest-full-py3
+ override-checkout: stable/train
- job:
name: tempest-full-stein
@@ -622,6 +653,10 @@
- tempest-full-py3-ipv6:
voting: false
irrelevant-files: *tempest-irrelevant-files
+ - tempest-full-train:
+ irrelevant-files: *tempest-irrelevant-files
+ - tempest-full-train-py3:
+ irrelevant-files: *tempest-irrelevant-files
- tempest-full-stein:
irrelevant-files: *tempest-irrelevant-files
- tempest-full-stein-py3:
@@ -663,8 +698,6 @@
irrelevant-files: *tempest-irrelevant-files
- neutron-grenade-multinode:
irrelevant-files: *tempest-irrelevant-files
- - neutron-grenade:
- irrelevant-files: *tempest-irrelevant-files
- grenade-py3:
irrelevant-files: *tempest-irrelevant-files
- devstack-plugin-ceph-tempest:
@@ -694,7 +727,8 @@
- tempest-full-test-account-no-admin-py3:
voting: false
irrelevant-files: *tempest-irrelevant-files
- - openstack-tox-bashate
+ - openstack-tox-bashate:
+ irrelevant-files: *tempest-irrelevant-files-2
gate:
jobs:
- tempest-slow-py3:
@@ -703,8 +737,6 @@
irrelevant-files: *tempest-irrelevant-files
- tempest-full:
irrelevant-files: *tempest-irrelevant-files
- - neutron-grenade:
- irrelevant-files: *tempest-irrelevant-files
- grenade-py3:
irrelevant-files: *tempest-irrelevant-files
- tempest-ipv6-only:
@@ -727,10 +759,12 @@
irrelevant-files: *tempest-irrelevant-files
- tempest-pg-full:
irrelevant-files: *tempest-irrelevant-files
- - tempest-full-py3-opensuse150:
+ - tempest-full-py3-opensuse15:
irrelevant-files: *tempest-irrelevant-files
periodic-stable:
jobs:
+ - tempest-full-train
+ - tempest-full-train-py3
- tempest-full-stein
- tempest-full-stein-py3
- tempest-full-rocky
diff --git a/doc/source/overview.rst b/doc/source/overview.rst
index 423214d..e51b90b 100644
--- a/doc/source/overview.rst
+++ b/doc/source/overview.rst
@@ -116,7 +116,7 @@
$ stestr run --black-regex '\[.*\bslow\b.*\]' '^tempest\.(api|scenario)'
will run the same set of tests as the default gate jobs. Or you can
- use `unittest`_ compatible test runners such as `testr`_, `pytest`_ etc.
+ use `unittest`_ compatible test runners such as `stestr`_, `pytest`_ etc.
Tox also contains several existing job configurations. For example::
@@ -130,7 +130,6 @@
to run the tests tagged as smoke.
.. _unittest: https://docs.python.org/3/library/unittest.html
-.. _testr: https://testrepository.readthedocs.org/en/latest/MANUAL.html
.. _stestr: https://stestr.readthedocs.org/en/latest/MANUAL.html
.. _pytest: https://docs.pytest.org/en/latest/
@@ -269,14 +268,14 @@
will have a configuration file already set up to work with your
DevStack installation.
-Tempest is not tied to any single test runner, but `testr`_ is the most commonly
+Tempest is not tied to any single test runner, but `stestr`_ is the most commonly
used tool. Also, the nosetests test runner is **not** recommended to run Tempest.
After setting up your configuration file, you can execute the set of Tempest
-tests by using ``testr`` ::
+tests by using ``stestr``. By default, ``stestr`` runs tests in parallel ::
- $ testr run --parallel
+ $ stestr run
To run one single test serially ::
- $ testr run tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_reboot_non_existent_server
+ $ stestr run --serial tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_reboot_non_existent_server
diff --git a/releasenotes/notes/Extend-cleanup-CLI-to-delete-regions-9f1dbda2c8de12e2.yaml b/releasenotes/notes/Extend-cleanup-CLI-to-delete-regions-9f1dbda2c8de12e2.yaml
new file mode 100644
index 0000000..e2fc5b3
--- /dev/null
+++ b/releasenotes/notes/Extend-cleanup-CLI-to-delete-regions-9f1dbda2c8de12e2.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ tempest cleanup CLI is extended about region deletion. Until now, the
+ regions have been neglected by tempest cleanup. From now on, tempest
+ cleanup is able to delete leftover regions as well.
diff --git a/releasenotes/notes/fix-1847749-2670b1d4f6097a1a.yaml b/releasenotes/notes/fix-1847749-2670b1d4f6097a1a.yaml
new file mode 100644
index 0000000..4842f63
--- /dev/null
+++ b/releasenotes/notes/fix-1847749-2670b1d4f6097a1a.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+ - |
+ Bug#1847749. This provides the workaround of Skip Exception raised instead of skipping
+ the CLI tests. If you are running Tempest with stestr > 2.5.0 then use this fix.
+ Ref- https://github.com/testing-cabal/testtools/issues/272
diff --git a/releasenotes/notes/intermediate-ussuri-release-8aebeca312a6718c.yaml b/releasenotes/notes/intermediate-ussuri-release-8aebeca312a6718c.yaml
new file mode 100644
index 0000000..6caeacd
--- /dev/null
+++ b/releasenotes/notes/intermediate-ussuri-release-8aebeca312a6718c.yaml
@@ -0,0 +1,14 @@
+---
+prelude: >
+ This is an intermediate release during the Ussuri development cycle to
+ mark the end of support for EM Queens in Tempest.
+ After this release, Tempest will support below OpenStack Releases:
+
+ * Train
+ * Stein
+ * Rocky
+
+ Current development of Tempest is for OpenStack Ussuri development
+ cycle.
+
+ This is the last release of Tempest to officially support python2.7.
diff --git a/releasenotes/notes/subunit_describe_calls-ad7df689b9d63e3f.yaml b/releasenotes/notes/subunit_describe_calls-ad7df689b9d63e3f.yaml
new file mode 100644
index 0000000..e7fc3a0
--- /dev/null
+++ b/releasenotes/notes/subunit_describe_calls-ad7df689b9d63e3f.yaml
@@ -0,0 +1,8 @@
+---
+deprecations:
+ - |
+ Deprecated command for subunit-describe-calls
+
+features:
+ - |
+ Added new tempest subcommand for subunit-describe-calls
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index 1d0d914..bfd8b2d 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -6,6 +6,9 @@
:maxdepth: 1
unreleased
+ v23.0.0
+ v22.1.0
+ v22.0.0
v21.0.0
v20.0.0
v19.0.0
diff --git a/releasenotes/source/v22.0.0.rst b/releasenotes/source/v22.0.0.rst
new file mode 100644
index 0000000..519b081
--- /dev/null
+++ b/releasenotes/source/v22.0.0.rst
@@ -0,0 +1,6 @@
+=====================
+v22.0.0 Release Notes
+=====================
+
+.. release-notes:: 22.0.0 Release Notes
+ :version: 22.0.0
diff --git a/releasenotes/source/v22.1.0.rst b/releasenotes/source/v22.1.0.rst
new file mode 100644
index 0000000..6a4fd1f
--- /dev/null
+++ b/releasenotes/source/v22.1.0.rst
@@ -0,0 +1,6 @@
+=====================
+v22.1.0 Release Notes
+=====================
+
+.. release-notes:: 22.1.0 Release Notes
+ :version: 22.1.0
diff --git a/releasenotes/source/v23.0.0.rst b/releasenotes/source/v23.0.0.rst
new file mode 100644
index 0000000..7c5edf8
--- /dev/null
+++ b/releasenotes/source/v23.0.0.rst
@@ -0,0 +1,6 @@
+=====================
+v23.0.0 Release Notes
+=====================
+
+.. release-notes:: 23.0.0 Release Notes
+ :version: 23.0.0
diff --git a/setup.cfg b/setup.cfg
index 5c1d24c..1e9b8e9 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -36,6 +36,7 @@
subunit-describe-calls = tempest.cmd.subunit_describe_calls:entry_point
tempest.cm =
account-generator = tempest.cmd.account_generator:TempestAccountGenerator
+ subunit-describe-calls = tempest.cmd.subunit_describe_calls:TempestSubunitDescribeCalls
init = tempest.cmd.init:TempestInit
cleanup = tempest.cmd.cleanup:TempestCleanup
list-plugins = tempest.cmd.list_plugins:TempestListPlugins
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index b1a7c52..836b975 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -31,6 +31,13 @@
class LiveMigrationTestBase(base.BaseV2ComputeAdminTest):
+ # These tests don't attempt any SSH validation nor do they use
+ # floating IPs on the instance, so all we need is a network and
+ # a subnet so the instance being migrated has a single port, but
+ # we need that to make sure we are properly updating the port
+ # host bindings during the live migration.
+ create_default_network = True
+
@classmethod
def skip_checks(cls):
super(LiveMigrationTestBase, cls).skip_checks()
@@ -44,16 +51,6 @@
"Less than 2 compute nodes, skipping migration test.")
@classmethod
- def setup_credentials(cls):
- # These tests don't attempt any SSH validation nor do they use
- # floating IPs on the instance, so all we need is a network and
- # a subnet so the instance being migrated has a single port, but
- # we need that to make sure we are properly updating the port
- # host bindings during the live migration.
- cls.set_network_resources(network=True, subnet=True)
- super(LiveMigrationTestBase, cls).setup_credentials()
-
- @classmethod
def setup_clients(cls):
super(LiveMigrationTestBase, cls).setup_clients()
cls.admin_migration_client = cls.os_admin.migrations_client
diff --git a/tempest/api/compute/admin/test_security_group_default_rules.py b/tempest/api/compute/admin/test_security_group_default_rules.py
deleted file mode 100644
index bca6a22..0000000
--- a/tempest/api/compute/admin/test_security_group_default_rules.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# Copyright 2014 NEC Corporation. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import testtools
-
-from tempest.api.compute import base
-from tempest import config
-from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-
-CONF = config.CONF
-
-
-class SecurityGroupDefaultRulesTest(base.BaseV2ComputeAdminTest):
- max_microversion = '2.35'
-
- @classmethod
- # TODO(GMann): Once Bug# 1311500 is fixed, these test can run
- # for Neutron also.
- @testtools.skipIf(CONF.service_available.neutron,
- "Skip as this functionality is not yet "
- "implemented in Neutron. Related Bug#1311500")
- def setup_credentials(cls):
- # A network and a subnet will be created for these tests
- cls.set_network_resources(network=True, subnet=True)
- super(SecurityGroupDefaultRulesTest, cls).setup_credentials()
-
- @classmethod
- def setup_clients(cls):
- super(SecurityGroupDefaultRulesTest, cls).setup_clients()
- cls.adm_client = cls.os_admin.security_group_default_rules_client
-
- def _create_security_group_default_rules(self, ip_protocol='tcp',
- from_port=22, to_port=22,
- cidr='10.10.0.0/24'):
- # Create Security Group default rule
- rule = self.adm_client.create_security_default_group_rule(
- ip_protocol=ip_protocol,
- from_port=from_port,
- to_port=to_port,
- cidr=cidr)['security_group_default_rule']
- self.assertEqual(ip_protocol, rule['ip_protocol'])
- self.assertEqual(from_port, rule['from_port'])
- self.assertEqual(to_port, rule['to_port'])
- self.assertEqual(cidr, rule['ip_range']['cidr'])
- return rule
-
- @decorators.idempotent_id('6d880615-eec3-4d29-97c5-7a074dde239d')
- def test_create_delete_security_group_default_rules(self):
- # Create and delete Security Group default rule
- ip_protocols = ['tcp', 'udp', 'icmp']
- for ip_protocol in ip_protocols:
- rule = self._create_security_group_default_rules(ip_protocol)
- # Delete Security Group default rule
- self.adm_client.delete_security_group_default_rule(rule['id'])
- self.assertRaises(lib_exc.NotFound,
- self.adm_client.show_security_group_default_rule,
- rule['id'])
-
- @decorators.idempotent_id('4d752e0a-33a1-4c3a-b498-ff8667ca22e5')
- def test_create_security_group_default_rule_without_cidr(self):
- ip_protocol = 'udp'
- from_port = 80
- to_port = 80
- rule = self.adm_client.create_security_default_group_rule(
- ip_protocol=ip_protocol,
- from_port=from_port,
- to_port=to_port)['security_group_default_rule']
- self.addCleanup(self.adm_client.delete_security_group_default_rule,
- rule['id'])
- self.assertNotEqual(0, rule['id'])
- self.assertEqual('0.0.0.0/0', rule['ip_range']['cidr'])
-
- @decorators.idempotent_id('29f2d218-69b0-4a95-8f3d-6bd0ef732b3a')
- def test_create_security_group_default_rule_with_blank_cidr(self):
- ip_protocol = 'icmp'
- from_port = 10
- to_port = 10
- cidr = ''
- rule = self.adm_client.create_security_default_group_rule(
- ip_protocol=ip_protocol,
- from_port=from_port,
- to_port=to_port,
- cidr=cidr)['security_group_default_rule']
- self.addCleanup(self.adm_client.delete_security_group_default_rule,
- rule['id'])
- self.assertNotEqual(0, rule['id'])
- self.assertEqual('0.0.0.0/0', rule['ip_range']['cidr'])
-
- @decorators.idempotent_id('6e6de55e-9146-4ae0-89f2-3569586e0b9b')
- def test_security_group_default_rules_list(self):
- ip_protocol = 'tcp'
- from_port = 22
- to_port = 22
- cidr = '10.10.0.0/24'
- rule = self._create_security_group_default_rules(ip_protocol,
- from_port,
- to_port,
- cidr)
- self.addCleanup(self.adm_client.delete_security_group_default_rule,
- rule['id'])
- rules = (self.adm_client.list_security_group_default_rules()
- ['security_group_default_rules'])
- self.assertNotEmpty(rules)
- self.assertIn(rule, rules)
-
- @decorators.idempotent_id('15cbb349-86b4-4f71-a048-04b7ef3f150b')
- def test_default_security_group_default_rule_show(self):
- ip_protocol = 'tcp'
- from_port = 22
- to_port = 22
- cidr = '10.10.0.0/24'
- rule = self._create_security_group_default_rules(ip_protocol,
- from_port,
- to_port,
- cidr)
- self.addCleanup(self.adm_client.delete_security_group_default_rule,
- rule['id'])
- fetched_rule = self.adm_client.show_security_group_default_rule(
- rule['id'])['security_group_default_rule']
- self.assertEqual(rule, fetched_rule)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index aaf7a5a..7c2d9d2 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -39,6 +39,9 @@
"""Base test case class for all Compute API tests."""
force_tenant_isolation = False
+ # Set this to True in subclasses to create a default network. See
+ # https://bugs.launchpad.net/tempest/+bug/1844568
+ create_default_network = False
# TODO(andreaf) We should care also for the alt_manager here
# but only once client lazy load in the manager is done
@@ -58,7 +61,10 @@
@classmethod
def setup_credentials(cls):
- cls.set_network_resources()
+ # Setting network=True, subnet=True creates a default network
+ cls.set_network_resources(
+ network=cls.create_default_network,
+ subnet=cls.create_default_network)
super(BaseV2ComputeTest, cls).setup_credentials()
@classmethod
diff --git a/tempest/api/compute/security_groups/base.py b/tempest/api/compute/security_groups/base.py
index 49125d1..ef69a13 100644
--- a/tempest/api/compute/security_groups/base.py
+++ b/tempest/api/compute/security_groups/base.py
@@ -24,18 +24,14 @@
class BaseSecurityGroupsTest(base.BaseV2ComputeTest):
max_microversion = '2.35'
+ create_default_network = True
+
@classmethod
def skip_checks(cls):
super(BaseSecurityGroupsTest, cls).skip_checks()
if not utils.get_service_list()['network']:
raise cls.skipException("network service not enabled.")
- @classmethod
- def setup_credentials(cls):
- # A network and a subnet will be created for these tests
- cls.set_network_resources(network=True, subnet=True)
- super(BaseSecurityGroupsTest, cls).setup_credentials()
-
@staticmethod
def generate_random_security_group_id():
if (CONF.service_available.neutron and
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 0263b81..a7db88a 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -26,6 +26,7 @@
class DeleteServersTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
# NOTE: Server creations of each test class should be under 10
# for preventing "Quota exceeded for instances"
diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py
index bc48069..5b8e7ab 100644
--- a/tempest/api/compute/servers/test_disk_config.py
+++ b/tempest/api/compute/servers/test_disk_config.py
@@ -24,6 +24,7 @@
class ServerDiskConfigTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
@classmethod
def skip_checks(cls):
diff --git a/tempest/api/compute/servers/test_instance_actions.py b/tempest/api/compute/servers/test_instance_actions.py
index b916a42..00837eb 100644
--- a/tempest/api/compute/servers/test_instance_actions.py
+++ b/tempest/api/compute/servers/test_instance_actions.py
@@ -19,6 +19,7 @@
class InstanceActionsTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
@classmethod
def setup_clients(cls):
@@ -54,6 +55,7 @@
class InstanceActionsV221TestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
min_microversion = '2.21'
max_microversion = 'latest'
diff --git a/tempest/api/compute/servers/test_instance_actions_negative.py b/tempest/api/compute/servers/test_instance_actions_negative.py
index 1d3a790..4b5a2c3 100644
--- a/tempest/api/compute/servers/test_instance_actions_negative.py
+++ b/tempest/api/compute/servers/test_instance_actions_negative.py
@@ -20,6 +20,7 @@
class InstanceActionsNegativeTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index f0915de..b95db5c 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -20,6 +20,7 @@
class ListServersNegativeTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index 059454d..e176251 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -19,6 +19,7 @@
class MultipleCreateTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
@decorators.idempotent_id('61e03386-89c3-449c-9bb1-a06f423fd9d1')
def test_multiple_create(self):
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index 7cf6d83..68e09e7 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -33,6 +33,7 @@
class NoVNCConsoleTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
@classmethod
def skip_checks(cls):
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 0e469c7..ff50836 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -707,16 +707,13 @@
@testtools.skipUnless(CONF.compute_feature_enabled.vnc_console,
'VNC Console feature is disabled.')
def test_get_vnc_console(self):
- # Get the VNC console of type 'novnc' and 'xvpvnc'
- console_types = ['novnc', 'xvpvnc']
- for console_type in console_types:
- if self.is_requested_microversion_compatible('2.5'):
- body = self.client.get_vnc_console(
- self.server_id, type=console_type)['console']
- else:
- body = self.client.get_remote_console(
- self.server_id, console_type=console_type,
- protocol='vnc')['remote_console']
- self.assertEqual(console_type, body['type'])
- self.assertNotEqual('', body['url'])
- self._validate_url(body['url'])
+ if self.is_requested_microversion_compatible('2.5'):
+ body = self.client.get_vnc_console(
+ self.server_id, type='novnc')['console']
+ else:
+ body = self.client.get_remote_console(
+ self.server_id, console_type='novnc',
+ protocol='vnc')['remote_console']
+ self.assertEqual('novnc', body['type'])
+ self.assertNotEqual('', body['url'])
+ self._validate_url(body['url'])
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index f79b05f..c936ce5 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -19,12 +19,7 @@
class ServerAddressesTestJSON(base.BaseV2ComputeTest):
-
- @classmethod
- def setup_credentials(cls):
- # This test module might use a network and a subnet
- cls.set_network_resources(network=True, subnet=True)
- super(ServerAddressesTestJSON, cls).setup_credentials()
+ create_default_network = True
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index b2b3cc0..f33c6d9 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -20,11 +20,7 @@
class ServerAddressesNegativeTestJSON(base.BaseV2ComputeTest):
-
- @classmethod
- def setup_credentials(cls):
- cls.set_network_resources(network=True, subnet=True)
- super(ServerAddressesNegativeTestJSON, cls).setup_credentials()
+ create_default_network = True
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/servers/test_server_group.py b/tempest/api/compute/servers/test_server_group.py
index 1b7cb96..4b5efaa 100644
--- a/tempest/api/compute/servers/test_server_group.py
+++ b/tempest/api/compute/servers/test_server_group.py
@@ -29,6 +29,7 @@
policies = affinity/anti-affinity
It also adds the tests for list and get details of server-groups
"""
+ create_default_network = True
@classmethod
def skip_checks(cls):
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index fe95018..9d87e1c 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -18,6 +18,7 @@
class ServerMetadataTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/servers/test_server_password.py b/tempest/api/compute/servers/test_server_password.py
index e6a668a..7b31ede 100644
--- a/tempest/api/compute/servers/test_server_password.py
+++ b/tempest/api/compute/servers/test_server_password.py
@@ -19,6 +19,7 @@
class ServerPasswordTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/compute/servers/test_server_tags.py b/tempest/api/compute/servers/test_server_tags.py
index 8d0a4e3..3893b01 100644
--- a/tempest/api/compute/servers/test_server_tags.py
+++ b/tempest/api/compute/servers/test_server_tags.py
@@ -26,6 +26,8 @@
min_microversion = '2.26'
max_microversion = 'latest'
+ create_default_network = True
+
@classmethod
def skip_checks(cls):
super(ServerTagsTestJSON, cls).skip_checks()
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 1e3e966..3a4bd6d 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -25,6 +25,7 @@
class ServersTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 6cabf65..f42bb9c 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -30,6 +30,7 @@
class ServersNegativeTestJSON(base.BaseV2ComputeTest):
+ create_default_network = True
def setUp(self):
super(ServersNegativeTestJSON, self).setUp()
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index f810ec5..dfd6ca4 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -32,11 +32,7 @@
depends_on_nova_network = True
- @classmethod
- def setup_credentials(cls):
- # This test needs a network and a subnet
- cls.set_network_resources(network=True, subnet=True)
- super(VirtualInterfacesTestJSON, cls).setup_credentials()
+ create_default_network = True
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index f83e62c..bee2b7b 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -28,6 +28,7 @@
class BaseAttachVolumeTest(base.BaseV2ComputeTest):
"""Base class for the attach volume tests in this module."""
+ create_default_network = True
@classmethod
def skip_checks(cls):
@@ -41,11 +42,6 @@
cls.prepare_instance_network()
super(BaseAttachVolumeTest, cls).setup_credentials()
- @classmethod
- def resource_setup(cls):
- super(BaseAttachVolumeTest, cls).resource_setup()
- cls.device = CONF.compute.volume_device_name
-
def _create_server(self):
# Start a server and wait for it to become ready
validation_resources = self.get_test_validation_resources(
@@ -84,15 +80,18 @@
# NOTE(andreaf) We need to ensure the ssh key has been
# injected in the guest before we power cycle
linux_client.validate_authentication()
+ disks_before_attach = linux_client.count_disks()
volume = self.create_volume()
# NOTE: As of the 12.0.0 Liberty release, the Nova libvirt driver
- # no longer honors a user-supplied device name, in that case
- # CONF.compute.volume_device_name must be set the equal value as
- # the libvirt auto-assigned one
- attachment = self.attach_volume(server, volume,
- device=('/dev/%s' % self.device))
+ # no longer honors a user-supplied device name, and there can be
+ # a mismatch between libvirt provide disk name and actual disk name
+ # on instance, hence we no longer validate this test with the supplied
+ # device name rather we count number of disk before attach
+ # detach to validate the testcase.
+
+ attachment = self.attach_volume(server, volume)
self.servers_client.stop_server(server['id'])
waiters.wait_for_server_status(self.servers_client, server['id'],
@@ -103,9 +102,8 @@
'ACTIVE')
if CONF.validation.run_validation:
- disks = linux_client.get_disks()
- device_name_to_match = '\n' + self.device + ' '
- self.assertIn(device_name_to_match, disks)
+ disks_after_attach = linux_client.count_disks()
+ self.assertGreater(disks_after_attach, disks_before_attach)
self.servers_client.detach_volume(server['id'], attachment['volumeId'])
waiters.wait_for_volume_resource_status(
@@ -120,8 +118,8 @@
'ACTIVE')
if CONF.validation.run_validation:
- disks = linux_client.get_disks()
- self.assertNotIn(device_name_to_match, disks)
+ disks_after_detach = linux_client.count_disks()
+ self.assertEqual(disks_before_attach, disks_after_detach)
@decorators.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513')
def test_list_get_volume_attachments(self):
diff --git a/tempest/api/compute/volumes/test_attach_volume_negative.py b/tempest/api/compute/volumes/test_attach_volume_negative.py
index 6d08f90..9a506af 100644
--- a/tempest/api/compute/volumes/test_attach_volume_negative.py
+++ b/tempest/api/compute/volumes/test_attach_volume_negative.py
@@ -21,6 +21,7 @@
class AttachVolumeNegativeTest(base.BaseV2ComputeTest):
+ create_default_network = True
@classmethod
def skip_checks(cls):
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
deleted file mode 100644
index eaf477c..0000000
--- a/tempest/api/network/admin/test_agent_management.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# Copyright 2013 IBM Corp.
-#
-# 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.network import base
-from tempest.common import tempest_fixtures as fixtures
-from tempest.common import utils
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-
-
-class AgentManagementTestJSON(base.BaseAdminNetworkTest):
-
- @classmethod
- def skip_checks(cls):
- super(AgentManagementTestJSON, cls).skip_checks()
- if not utils.is_extension_enabled('agent', 'network'):
- msg = "agent extension not enabled."
- raise cls.skipException(msg)
-
- @classmethod
- def resource_setup(cls):
- super(AgentManagementTestJSON, cls).resource_setup()
- body = cls.admin_agents_client.list_agents()
- agents = body['agents']
- cls.agent = agents[0]
-
- @decorators.idempotent_id('9c80f04d-11f3-44a4-8738-ed2f879b0ff4')
- def test_list_agent(self):
- body = self.admin_agents_client.list_agents()
- agents = body['agents']
- # Hearthbeats must be excluded from comparison
- self.agent.pop('heartbeat_timestamp', None)
- self.agent.pop('configurations', None)
- for agent in agents:
- agent.pop('heartbeat_timestamp', None)
- agent.pop('configurations', None)
- self.assertIn(self.agent, agents)
-
- @decorators.idempotent_id('869bc8e8-0fda-4a30-9b71-f8a7cf58ca9f')
- def test_show_agent(self):
- body = self.admin_agents_client.show_agent(self.agent['id'])
- agent = body['agent']
- self.assertEqual(agent['id'], self.agent['id'])
-
- @decorators.idempotent_id('371dfc5b-55b9-4cb5-ac82-c40eadaac941')
- def test_update_agent_status(self):
- origin_status = self.agent['admin_state_up']
- # Try to update the 'admin_state_up' to the original
- # one to avoid the negative effect.
- agent_status = {'admin_state_up': origin_status}
- body = self.admin_agents_client.update_agent(agent_id=self.agent['id'],
- agent=agent_status)
- updated_status = body['agent']['admin_state_up']
- self.assertEqual(origin_status, updated_status)
-
- @decorators.idempotent_id('68a94a14-1243-46e6-83bf-157627e31556')
- def test_update_agent_description(self):
- self.useFixture(fixtures.LockFixture('agent_description'))
- description = 'description for update agent.'
- agent_description = {'description': description}
- body = self.admin_agents_client.update_agent(agent_id=self.agent['id'],
- agent=agent_description)
- self.addCleanup(self._restore_agent)
- updated_description = body['agent']['description']
- self.assertEqual(updated_description, description)
-
- def _restore_agent(self):
- """Restore the agent description after update test"""
-
- description = self.agent['description'] or ''
- origin_agent = {'description': description}
- self.admin_agents_client.update_agent(agent_id=self.agent['id'],
- agent=origin_agent)
-
- @decorators.idempotent_id('b33af888-b6ac-4e68-a0ca-0444c2696cf9')
- @decorators.attr(type=['negative'])
- def test_delete_agent_negative(self):
- non_existent_id = data_utils.rand_uuid()
- self.assertRaises(
- lib_exc.NotFound,
- self.admin_agents_client.delete_agent, non_existent_id)
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 56b5509..10121de 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -197,14 +197,14 @@
'Ports from multiple tenants are in the list resp')
port_ids = [port['id'] for port in ports]
fixed_ips = [port['fixed_ips'] for port in ports]
- port_ips = []
- for addr in fixed_ips:
- port_ips.extend([port['ip_address'] for port in addr])
-
port_net_ids = [port['network_id'] for port in ports]
self.assertIn(port_1['port']['id'], port_ids)
- self.assertIn(port_1_fixed_ip, port_ips)
self.assertIn(network['id'], port_net_ids)
+ # Check that every port has a fixed_ip that matches the query
+ for addr in fixed_ips:
+ port_ips = [port['ip_address'] for port in addr]
+ self.assertIn(port_1_fixed_ip, port_ips,
+ 'Port not matching IP filter found')
@decorators.idempotent_id('79895408-85d5-460d-94e7-9531c5fd9123')
@testtools.skipUnless(
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index 645a952..c54b16b 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -135,10 +135,11 @@
self.admin_project_id = ""
self._init_admin_ids()
- self.admin_role_added = []
-
# available services
- self.project_services = cleanup_service.get_project_cleanup_services()
+ self.project_associated_services = (
+ cleanup_service.get_project_associated_cleanup_services())
+ self.resource_cleanup_services = (
+ cleanup_service.get_resource_cleanup_services())
self.global_services = cleanup_service.get_global_cleanup_services()
if parsed_args.init_saved_state:
@@ -170,7 +171,6 @@
# Loop through list of projects and clean them up.
for project in projects:
- self._add_admin(project['id'])
self._clean_project(project)
kwargs = {'data': self.dry_run_data,
@@ -183,20 +183,15 @@
svc = service(admin_mgr, **kwargs)
svc.run()
+ for service in self.resource_cleanup_services:
+ svc = service(self.admin_mgr, **kwargs)
+ svc.run()
+
if is_dry_run:
with open(DRY_RUN_JSON, 'w+') as f:
f.write(json.dumps(self.dry_run_data, sort_keys=True,
indent=2, separators=(',', ': ')))
- self._remove_admin_user_roles()
-
- def _remove_admin_user_roles(self):
- project_ids = self.admin_role_added
- LOG.debug("Removing admin user roles where needed for projects: %s",
- project_ids)
- for project_id in project_ids:
- self._remove_admin_role(project_id)
-
def _clean_project(self, project):
print("Cleaning project: %s " % project['name'])
is_dry_run = self.options.dry_run
@@ -209,11 +204,6 @@
project_data = dry_run_data["_projects_to_clean"][project_id] = {}
project_data['name'] = project_name
- kwargs = {"username": CONF.auth.admin_username,
- "password": CONF.auth.admin_password,
- "project_name": project['name']}
- mgr = clients.Manager(credentials=credentials.get_credentials(
- **kwargs))
kwargs = {'data': project_data,
'is_dry_run': is_dry_run,
'saved_state_json': self.json_data,
@@ -221,8 +211,8 @@
'is_save_state': False,
'project_id': project_id,
'got_exceptions': self.GOT_EXCEPTIONS}
- for service in self.project_services:
- svc = service(mgr, **kwargs)
+ for service in self.project_associated_services:
+ svc = service(self.admin_mgr, **kwargs)
svc.run()
def _init_admin_ids(self):
@@ -272,46 +262,6 @@
def get_description(self):
return 'Cleanup after tempest run'
- def _add_admin(self, project_id):
- rl_cl = self.admin_mgr.roles_v3_client
- needs_role = True
- roles = rl_cl.list_user_roles_on_project(project_id,
- self.admin_id)['roles']
- for role in roles:
- if role['id'] == self.admin_role_id:
- needs_role = False
- LOG.debug("User already had admin privilege for this project")
- if needs_role:
- LOG.debug("Adding admin privilege for : %s", project_id)
- rl_cl.create_user_role_on_project(project_id, self.admin_id,
- self.admin_role_id)
- self.admin_role_added.append(project_id)
-
- def _remove_admin_role(self, project_id):
- LOG.debug("Remove admin user role for projectt: %s", project_id)
- # Must initialize Admin Manager for each user role
- # Otherwise authentication exception is thrown, weird
- id_cl = clients.Manager(
- credentials.get_configured_admin_credentials()).identity_client
- if (self._project_exists(project_id)):
- try:
- id_cl.delete_role_from_user_on_project(project_id,
- self.admin_id,
- self.admin_role_id)
- except Exception as ex:
- LOG.exception("Failed removing role from project which still "
- "exists, exception: %s", ex)
-
- def _project_exists(self, project_id):
- pr_cl = self.admin_mgr.projects_client
- try:
- p = pr_cl.show_project(project_id)
- LOG.debug("Project is: %s", str(p))
- return True
- except Exception as ex:
- LOG.debug("Project no longer exists? %s", ex)
- return False
-
def _init_state(self):
print("Initializing saved state.")
data = {}
@@ -326,7 +276,11 @@
svc = service(admin_mgr, **kwargs)
svc.run()
- for service in self.project_services:
+ for service in self.project_associated_services:
+ svc = service(admin_mgr, **kwargs)
+ svc.run()
+
+ for service in self.resource_cleanup_services:
svc = service(admin_mgr, **kwargs)
svc.run()
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 8b625d0..2b35ebf 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -730,6 +730,44 @@
# begin global services
+class RegionService(BaseService):
+
+ def __init__(self, manager, **kwargs):
+ super(RegionService, self).__init__(kwargs)
+ self.client = manager.regions_client
+
+ def list(self):
+ client = self.client
+ regions = client.list_regions()
+ if not self.is_save_state:
+ regions = [region for region in regions['regions'] if region['id']
+ not in self.saved_state_json['regions'].keys()]
+ return regions
+ else:
+ return regions['regions']
+
+ def delete(self):
+ client = self.client
+ regions = self.list()
+ for region in regions:
+ try:
+ client.delete_region(region['id'])
+ except Exception:
+ LOG.exception("Delete Region %s exception.", region['id'])
+
+ def dry_run(self):
+ regions = self.list()
+ self.data['regions'] = {}
+ for region in regions:
+ self.data['regions'][region['id']] = region
+
+ def save_state(self):
+ regions = self.list()
+ self.data['regions'] = {}
+ for region in regions:
+ self.data['regions'][region['id']] = region
+
+
class FlavorService(BaseService):
def __init__(self, manager, **kwargs):
super(FlavorService, self).__init__(kwargs)
@@ -968,31 +1006,52 @@
self.data['domains'][domain['id']] = domain['name']
-def get_project_cleanup_services():
- project_services = []
+def get_project_associated_cleanup_services():
+ """Returns list of project service classes.
+
+ The list contains services whose resources need to be deleted prior,
+ the project they are associated with, deletion. The resources cannot be
+ most likely deleted after the project is deleted first.
+ """
+ project_associated_services = []
# TODO(gmann): Tempest should provide some plugin hook for cleanup
# script extension to plugin tests also.
if IS_NOVA:
- project_services.append(ServerService)
- project_services.append(KeyPairService)
- project_services.append(ServerGroupService)
- project_services.append(NovaQuotaService)
- if IS_NEUTRON:
- project_services.append(NetworkFloatingIpService)
- if utils.is_extension_enabled('metering', 'network'):
- project_services.append(NetworkMeteringLabelRuleService)
- project_services.append(NetworkMeteringLabelService)
- project_services.append(NetworkRouterService)
- project_services.append(NetworkPortService)
- project_services.append(NetworkSubnetService)
- project_services.append(NetworkService)
- project_services.append(NetworkSecGroupService)
- project_services.append(NetworkSubnetPoolsService)
+ project_associated_services.append(NovaQuotaService)
if IS_CINDER:
- project_services.append(SnapshotService)
- project_services.append(VolumeService)
- project_services.append(VolumeQuotaService)
- return project_services
+ project_associated_services.append(VolumeQuotaService)
+ return project_associated_services
+
+
+def get_resource_cleanup_services():
+ """Returns list of project related classes.
+
+ The list contains services whose resources are associated with a project,
+ however, their deletion is possible also after the project is deleted
+ first.
+ """
+ resource_cleanup_services = []
+ # TODO(gmann): Tempest should provide some plugin hook for cleanup
+ # script extension to plugin tests also.
+ if IS_NOVA:
+ resource_cleanup_services.append(ServerService)
+ resource_cleanup_services.append(KeyPairService)
+ resource_cleanup_services.append(ServerGroupService)
+ if IS_NEUTRON:
+ resource_cleanup_services.append(NetworkFloatingIpService)
+ if utils.is_extension_enabled('metering', 'network'):
+ resource_cleanup_services.append(NetworkMeteringLabelRuleService)
+ resource_cleanup_services.append(NetworkMeteringLabelService)
+ resource_cleanup_services.append(NetworkRouterService)
+ resource_cleanup_services.append(NetworkPortService)
+ resource_cleanup_services.append(NetworkSubnetService)
+ resource_cleanup_services.append(NetworkService)
+ resource_cleanup_services.append(NetworkSecGroupService)
+ resource_cleanup_services.append(NetworkSubnetPoolsService)
+ if IS_CINDER:
+ resource_cleanup_services.append(SnapshotService)
+ resource_cleanup_services.append(VolumeService)
+ return resource_cleanup_services
def get_global_cleanup_services():
@@ -1005,4 +1064,5 @@
global_services.append(ProjectService)
global_services.append(DomainService)
global_services.append(RoleService)
+ global_services.append(RegionService)
return global_services
diff --git a/tempest/cmd/subunit_describe_calls.py b/tempest/cmd/subunit_describe_calls.py
index 081fa7a..e029538 100644
--- a/tempest/cmd/subunit_describe_calls.py
+++ b/tempest/cmd/subunit_describe_calls.py
@@ -81,13 +81,19 @@
import os
import re
import sys
+import traceback
+from cliff.command import Command
from oslo_serialization import jsonutils as json
import subunit
import testtools
+DESCRIPTION = "Outputs all HTTP calls a given test made that were logged."
+
+
class UrlParser(testtools.TestResult):
+
uuid_re = re.compile(r'(^|[^0-9a-f])[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-'
'[0-9a-f]{4}-[0-9a-f]{12}([^0-9a-f]|$)')
id_re = re.compile(r'(^|[^0-9a-z])[0-9a-z]{8}[0-9a-z]{4}[0-9a-z]{4}'
@@ -241,33 +247,12 @@
class ArgumentParser(argparse.ArgumentParser):
+
def __init__(self):
- desc = "Outputs all HTTP calls a given test made that were logged."
+ desc = DESCRIPTION
super(ArgumentParser, self).__init__(description=desc)
-
self.prog = "subunit-describe-calls"
-
- self.add_argument(
- "-s", "--subunit", metavar="<subunit file>",
- nargs="?", type=argparse.FileType('rb'), default=sys.stdin,
- help="The path to the subunit output file.")
-
- self.add_argument(
- "-n", "--non-subunit-name", metavar="<non subunit name>",
- default="pythonlogging",
- help="The name used in subunit to describe the file contents.")
-
- self.add_argument(
- "-o", "--output-file", metavar="<output file>", default=None,
- help="The output file name for the json.")
-
- self.add_argument(
- "-p", "--ports", metavar="<ports file>", default=None,
- help="A JSON file describing the ports for each service.")
-
- self.add_argument(
- "-v", "--verbose", action='store_true', default=False,
- help="Add Request and Response header and body data to stdout.")
+ _parser_add_args(self)
def parse(stream, non_subunit_name, ports):
@@ -321,11 +306,63 @@
sys.stdout.write('\n')
-def entry_point():
- cl_args = ArgumentParser().parse_args()
+def entry_point(cl_args=None):
+ print('Running subunit_describe_calls ...')
+ if not cl_args:
+ print("Use of: 'subunit-describe-calls' is deprecated, "
+ "please use: 'tempest subunit-describe-calls'")
+ cl_args = ArgumentParser().parse_args()
parser = parse(cl_args.subunit, cl_args.non_subunit_name, cl_args.ports)
output(parser, cl_args.output_file, cl_args.verbose)
+def _parser_add_args(parser):
+ parser.add_argument(
+ "-s", "--subunit", metavar="<subunit file>",
+ nargs="?", type=argparse.FileType('rb'), default=sys.stdin,
+ help="The path to the subunit output file(default:stdin v1/v2 stream)"
+ )
+
+ parser.add_argument(
+ "-n", "--non-subunit-name", metavar="<non subunit name>",
+ default="pythonlogging",
+ help="The name used in subunit to describe the file contents."
+ )
+
+ parser.add_argument(
+ "-o", "--output-file", metavar="<output file>", default=None,
+ help="The output file name for the json."
+ )
+
+ parser.add_argument(
+ "-p", "--ports", metavar="<ports file>", default=None,
+ help="A JSON file describing the ports for each service."
+ )
+
+ parser.add_argument(
+ "-v", "--verbose", action='store_true', default=False,
+ help="Add Request and Response header and body data to stdout."
+ )
+
+
+class TempestSubunitDescribeCalls(Command):
+
+ def get_parser(self, prog_name):
+ parser = super(TempestSubunitDescribeCalls, self).get_parser(prog_name)
+ _parser_add_args(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ try:
+ entry_point(parsed_args)
+
+ except Exception:
+ traceback.print_exc()
+ raise
+
+ def get_description(self):
+ return DESCRIPTION
+
+
if __name__ == "__main__":
entry_point()
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index dad710c..5875da3 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -73,6 +73,13 @@
msg = "'TYPE' column is required but the output doesn't have it: "
raise tempest.lib.exceptions.TempestException(msg + output)
+ def count_disks(self):
+ disks_list = self.get_disks()
+ disks_list = [line[0] for line in
+ [device_name.split()
+ for device_name in disks_list.splitlines()][1:]]
+ return len(disks_list)
+
def get_boot_time(self):
cmd = 'cut -f1 -d. /proc/uptime'
boot_secs = self.exec_command(cmd)
diff --git a/tempest/config.py b/tempest/config.py
index d67d3e0..32cebc5 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -667,7 +667,7 @@
default=28,
help="The mask bits for project ipv4 subnets"),
cfg.StrOpt('project_network_v6_cidr',
- default="2003::/48",
+ default="2001:db8::/48",
help="The cidr block to allocate project ipv6 subnets from"),
cfg.IntOpt('project_network_v6_mask_bits',
default=64,
diff --git a/tempest/lib/api_schema/response/compute/v2_71/servers.py b/tempest/lib/api_schema/response/compute/v2_71/servers.py
index 0c526fb..5cf0f8a 100644
--- a/tempest/lib/api_schema/response/compute/v2_71/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_71/servers.py
@@ -69,7 +69,7 @@
# need to keep this schema in this file to have the generic way to select the
# right schema based on self.schema_versions_info mapping in service client.
# ****** Schemas unchanged since microversion 2.70 ***
-list_servers_details = copy.deepcopy(servers270.list_servers_detail)
+list_servers_detail = copy.deepcopy(servers270.list_servers_detail)
list_servers = copy.deepcopy(servers270.list_servers)
show_server_diagnostics = copy.deepcopy(servers270.show_server_diagnostics)
get_remote_consoles = copy.deepcopy(servers270.get_remote_consoles)
diff --git a/tempest/lib/base.py b/tempest/lib/base.py
index 3be55c0..74ae77c 100644
--- a/tempest/lib/base.py
+++ b/tempest/lib/base.py
@@ -14,11 +14,29 @@
# under the License.
import os
+import sys
import fixtures
+import pkg_resources
import testtools
+def _handle_skip_exception():
+ try:
+ stestr_version = pkg_resources.parse_version(
+ pkg_resources.get_distribution("stestr").version)
+ stestr_min = pkg_resources.parse_version('2.5.0')
+ new_stestr = (stestr_version >= stestr_min)
+ import unittest
+ import unittest2
+ if sys.version_info >= (3, 5) and new_stestr:
+ testtools.TestCase.skipException = unittest.case.SkipTest
+ else:
+ testtools.TestCase.skipException = unittest2.case.SkipTest
+ except Exception:
+ pass
+
+
class BaseTestCase(testtools.testcase.WithAttributes, testtools.TestCase):
setUpClassCalled = False
@@ -33,6 +51,18 @@
if hasattr(super(BaseTestCase, cls), 'setUpClass'):
super(BaseTestCase, cls).setUpClass()
cls.setUpClassCalled = True
+ # TODO(gmann): cls.handle_skip_exception is really workaround for
+ # testtools bug- https://github.com/testing-cabal/testtools/issues/272
+ # stestr which is used by Tempest internally to run the test switch
+ # the customize test runner(which use stdlib unittest) for >=py3.5
+ # else testtools.run.- https://github.com/mtreinish/stestr/pull/265
+ # These two test runner are not compatible due to skip exception
+ # handling(due to unittest2). testtools.run treat unittestt.SkipTest
+ # as error and stdlib unittest treat unittest2.case.SkipTest raised
+ # by testtools.TestCase.skipException.
+ # The below workaround can be removed once testtools fix issue# 272.
+ cls.orig_skip_exception = testtools.TestCase.skipException
+ _handle_skip_exception()
@classmethod
def tearDownClass(cls):
@@ -40,6 +70,7 @@
super(BaseTestCase, cls).tearDownClass()
def setUp(self):
+ testtools.TestCase.skipException = self.orig_skip_exception
super(BaseTestCase, self).setUp()
if not self.setUpClassCalled:
raise RuntimeError("setUpClass does not calls the super's "
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
index d4ec6ad..2ac1605 100644
--- a/tempest/lib/common/ssh.py
+++ b/tempest/lib/common/ssh.py
@@ -196,11 +196,13 @@
exit_status = channel.recv_exit_status()
- if 0 != exit_status:
- raise exceptions.SSHExecCommandFailed(
- command=cmd, exit_status=exit_status,
- stderr=err_data, stdout=out_data)
- return out_data
+ ssh.close()
+
+ if 0 != exit_status:
+ raise exceptions.SSHExecCommandFailed(
+ command=cmd, exit_status=exit_status,
+ stderr=err_data, stdout=out_data)
+ return out_data
def test_connection_auth(self):
"""Raises an exception when we can not connect to server via ssh."""
diff --git a/tempest/lib/services/compute/versions_client.py b/tempest/lib/services/compute/versions_client.py
index 8fbb136..c6e1783 100644
--- a/tempest/lib/services/compute/versions_client.py
+++ b/tempest/lib/services/compute/versions_client.py
@@ -12,8 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import time
-
from oslo_serialization import jsonutils as json
from tempest.lib.api_schema.response.compute.v2_1 import versions as schema
@@ -26,11 +24,7 @@
def list_versions(self):
version_url = self._get_base_version_url()
- start = time.time()
resp, body = self.raw_request(version_url, 'GET')
- end = time.time()
- self._log_request('GET', version_url, resp, secs=(end - start),
- resp_body=body)
self._error_checker(resp, body)
body = json.loads(body)
diff --git a/tempest/lib/services/identity/v3/versions_client.py b/tempest/lib/services/identity/v3/versions_client.py
index 441ee0d..f3a8986 100644
--- a/tempest/lib/services/identity/v3/versions_client.py
+++ b/tempest/lib/services/identity/v3/versions_client.py
@@ -12,8 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import time
-
from oslo_serialization import jsonutils as json
from tempest.lib.common import rest_client
@@ -26,11 +24,7 @@
"""List API versions"""
version_url = self._get_base_version_url()
- start = time.time()
resp, body = self.raw_request(version_url, 'GET')
- end = time.time()
- self._log_request('GET', version_url, resp, secs=(end - start),
- resp_body=body)
self._error_checker(resp, body)
self.expected_success(300, resp.status)
diff --git a/tempest/lib/services/image/v2/versions_client.py b/tempest/lib/services/image/v2/versions_client.py
index 1adc466..1b7f806 100644
--- a/tempest/lib/services/image/v2/versions_client.py
+++ b/tempest/lib/services/image/v2/versions_client.py
@@ -12,8 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import time
-
from oslo_serialization import jsonutils as json
from tempest.lib.common import rest_client
@@ -26,11 +24,7 @@
"""List API versions"""
version_url = self._get_base_version_url()
- start = time.time()
resp, body = self.raw_request(version_url, 'GET')
- end = time.time()
- self._log_request('GET', version_url, resp, secs=(end - start),
- resp_body=body)
self._error_checker(resp, body)
self.expected_success(300, resp.status)
diff --git a/tempest/lib/services/volume/v3/versions_client.py b/tempest/lib/services/volume/v3/versions_client.py
index 175f1f5..aa6c867 100644
--- a/tempest/lib/services/volume/v3/versions_client.py
+++ b/tempest/lib/services/volume/v3/versions_client.py
@@ -12,8 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import time
-
from six.moves.urllib.parse import urljoin
from oslo_serialization import jsonutils as json
@@ -34,14 +32,10 @@
"""
version_url = self._get_base_version_url()
- start = time.time()
resp, body = self.raw_request(version_url, 'GET')
- end = time.time()
# NOTE: We need a raw_request() here instead of request() call because
# "list API versions" API doesn't require an authentication and we can
# skip it with raw_request() call.
- self._log_request('GET', version_url, resp, secs=(end - start),
- resp_body=body)
self._error_checker(resp, body)
body = json.loads(body)
diff --git a/tempest/lib/services/volume/v3/volumes_client.py b/tempest/lib/services/volume/v3/volumes_client.py
index 14a3c48..4fb6d2e 100644
--- a/tempest/lib/services/volume/v3/volumes_client.py
+++ b/tempest/lib/services/volume/v3/volumes_client.py
@@ -349,7 +349,7 @@
For a full list of available parameters, please refer to the official
API reference:
- https://docs.openstack.org/api-ref/block-storage/v3/index.html#force-delete-a-volume
+ https://docs.openstack.org/api-ref/block-storage/v3/index.html#force-detach-a-volume
"""
post_body = json.dumps({'os-force_detach': kwargs})
url = 'volumes/%s/action' % volume_id
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index f03e9de..b1919d4 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -249,12 +249,16 @@
block_migration = (CONF.compute_feature_enabled.
block_migration_for_live_migration)
+ old_host = self.get_host_for_server(server['id'])
self.admin_servers_client.live_migrate_server(
server['id'], host=None, block_migration=block_migration,
disk_over_commit=False)
waiters.wait_for_server_status(self.servers_client,
server['id'], 'ACTIVE')
+ new_host = self.get_host_for_server(server['id'])
+ self.assertNotEqual(old_host, new_host, 'Server did not migrate')
+
self._wait_server_status_and_check_network_connectivity(
server, keypair, floating_ip)
diff --git a/tempest/test.py b/tempest/test.py
index 1e5cd19..f383bc1 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -20,7 +20,6 @@
import debtcollector.moves
import fixtures
from oslo_log import log as logging
-import pkg_resources
import six
import testtools
@@ -28,6 +27,7 @@
from tempest.common import credentials_factory as credentials
from tempest.common import utils
from tempest import config
+from tempest.lib import base as lib_base
from tempest.lib.common import fixed_network
from tempest.lib.common import profiler
from tempest.lib.common import validation_resources as vr
@@ -78,10 +78,6 @@
atexit.register(validate_tearDownClass)
-class DummyException(Exception):
- pass
-
-
class BaseTestCase(testtools.testcase.WithAttributes,
testtools.TestCase):
"""The test base class defines Tempest framework for class level fixtures.
@@ -145,26 +141,6 @@
cls._teardowns = []
@classmethod
- def handle_skip_exception(cls):
- try:
- stestr_version = pkg_resources.parse_version(
- pkg_resources.get_distribution("stestr").version)
- stestr_min = pkg_resources.parse_version('2.5.0')
- new_stestr = (stestr_version >= stestr_min)
- import unittest
- import unittest2
- if sys.version_info >= (3, 5) and new_stestr:
- exc = unittest2.case.SkipTest
- exc_to_raise = unittest.case.SkipTest
- else:
- exc = unittest.case.SkipTest
- exc_to_raise = unittest2.case.SkipTest
- except Exception:
- exc = DummyException
- exc_to_raise = DummyException
- return exc, exc_to_raise
-
- @classmethod
def setUpClass(cls):
cls.__setupclass_called = True
# Reset state
@@ -183,8 +159,9 @@
# as error and stdlib unittest treat unittest2.case.SkipTest raised
# by testtools.TestCase.skipException.
# The below workaround can be removed once testtools fix issue# 272.
+ orig_skip_exception = testtools.TestCase.skipException
+ lib_base._handle_skip_exception()
try:
- exc, exc_to_raise = cls.handle_skip_exception()
cls.skip_checks()
if not cls.__skip_checks_called:
@@ -202,12 +179,6 @@
# Additional class-wide test resources
cls._teardowns.append(('resources', cls.resource_cleanup))
cls.resource_setup()
- except exc as e:
- # NOTE(dviroel): the exception may be raised after setting up the
- # user credentials, so we must call tearDownClass to release all
- # allocated resources.
- cls.tearDownClass()
- raise exc_to_raise(e.args)
except Exception:
etype, value, trace = sys.exc_info()
LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.",
@@ -217,6 +188,8 @@
six.reraise(etype, value, trace)
finally:
del trace # to avoid circular refs
+ finally:
+ testtools.TestCase.skipException = orig_skip_exception
@classmethod
def tearDownClass(cls):
diff --git a/tempest/tests/cmd/test_cleanup_services.py b/tempest/tests/cmd/test_cleanup_services.py
index de0dbec..ae08d02 100644
--- a/tempest/tests/cmd/test_cleanup_services.py
+++ b/tempest/tests/cmd/test_cleanup_services.py
@@ -175,7 +175,8 @@
"ports": {u'aa74aa4v-741a': u'saved-port'},
"security_groups": {u'7q844add-3697': u'saved-sec-group'},
"subnets": {u'55ttda4a-2584': u'saved-subnet'},
- "subnetpools": {u'8acf64c1-43fc': u'saved-subnet-pool'}
+ "subnetpools": {u'8acf64c1-43fc': u'saved-subnet-pool'},
+ "regions": {u'RegionOne': {}}
}
# Mocked methods
get_method = 'tempest.lib.common.rest_client.RestClient.get'
@@ -1202,6 +1203,57 @@
# begin global services
+class TestRegionService(BaseCmdServiceTests):
+ service_class = 'RegionService'
+ service_name = 'regions'
+ response = {
+ "regions": [{
+ "parent_region_id": None,
+ "id": "RegionOne",
+ "links": {
+ "self":
+ "http://10.0.145.61:5000/v3/regions/RegionOne"
+ },
+ "description": ""
+ },
+ {
+ "parent_region_id": None,
+ "id": "RegionTwo",
+ "links": {
+ "self":
+ "http://10.0.145.61:5000/v3/regions/RegionTwo"
+ },
+ "description": ""
+ }],
+ "links": {
+ "self":
+ "http://10.0.145.61:5000/v3/regions",
+ "next": None,
+ "previous": None
+ }
+ }
+
+ def test_delete_pass(self):
+ delete_mock = [(self.get_method, self.response, 200),
+ (self.delete_method, None, 204),
+ (self.log_method, "exception", None)]
+ self._test_delete(delete_mock)
+
+ def test_delete_fail(self):
+ delete_mock = [(self.get_method, self.response, 200),
+ (self.delete_method, 'error', None),
+ (self.log_method, "exception", None)]
+ self._test_delete(delete_mock, fail=True)
+
+ def test_dry_run(self):
+ dry_mock = [(self.get_method, self.response, 200),
+ (self.delete_method, "delete", None)]
+ self._test_dry_run_true(dry_mock)
+
+ def test_save_state(self):
+ self._test_saved_state_true([(self.get_method, self.response, 200)])
+
+
class TestDomainService(BaseCmdServiceTests):
service_class = 'DomainService'
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index 02e1c99..6275f22 100755
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -54,44 +54,6 @@
waiters.wait_for_image_status,
self.client, 'fake_image_id', 'active')
- @mock.patch.object(time, 'sleep')
- def test_wait_for_volume_status_error_restoring(self, mock_sleep):
- # Tests that the wait method raises VolumeRestoreErrorException if
- # the volume status is 'error_restoring'.
- client = mock.Mock(spec=volumes_client.VolumesClient,
- resource_type="volume",
- build_interval=1)
- volume1 = {'volume': {'status': 'restoring-backup'}}
- volume2 = {'volume': {'status': 'error_restoring'}}
- mock_show = mock.Mock(side_effect=(volume1, volume2))
- client.show_volume = mock_show
- volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
- self.assertRaises(exceptions.VolumeRestoreErrorException,
- waiters.wait_for_volume_resource_status,
- client, volume_id, 'available')
- mock_show.assert_has_calls([mock.call(volume_id),
- mock.call(volume_id)])
- mock_sleep.assert_called_once_with(1)
-
- @mock.patch.object(time, 'sleep')
- def test_wait_for_volume_status_error_extending(self, mock_sleep):
- # Tests that the wait method raises VolumeExtendErrorException if
- # the volume status is 'error_extending'.
- client = mock.Mock(spec=volumes_client.VolumesClient,
- resource_type="volume",
- build_interval=1)
- volume1 = {'volume': {'status': 'extending'}}
- volume2 = {'volume': {'status': 'error_extending'}}
- mock_show = mock.Mock(side_effect=(volume1, volume2))
- client.show_volume = mock_show
- volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
- self.assertRaises(exceptions.VolumeExtendErrorException,
- waiters.wait_for_volume_resource_status,
- client, volume_id, 'available')
- mock_show.assert_has_calls([mock.call(volume_id),
- mock.call(volume_id)])
- mock_sleep.assert_called_once_with(1)
-
class TestInterfaceWaiters(base.TestCase):
@@ -232,3 +194,41 @@
show_volume.assert_has_calls([mock.call(mock.sentinel.volume_id),
mock.call(mock.sentinel.volume_id),
mock.call(mock.sentinel.volume_id)])
+
+ @mock.patch.object(time, 'sleep')
+ def test_wait_for_volume_status_error_restoring(self, mock_sleep):
+ # Tests that the wait method raises VolumeRestoreErrorException if
+ # the volume status is 'error_restoring'.
+ client = mock.Mock(spec=volumes_client.VolumesClient,
+ resource_type="volume",
+ build_interval=1)
+ volume1 = {'volume': {'status': 'restoring-backup'}}
+ volume2 = {'volume': {'status': 'error_restoring'}}
+ mock_show = mock.Mock(side_effect=(volume1, volume2))
+ client.show_volume = mock_show
+ volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
+ self.assertRaises(exceptions.VolumeRestoreErrorException,
+ waiters.wait_for_volume_resource_status,
+ client, volume_id, 'available')
+ mock_show.assert_has_calls([mock.call(volume_id),
+ mock.call(volume_id)])
+ mock_sleep.assert_called_once_with(1)
+
+ @mock.patch.object(time, 'sleep')
+ def test_wait_for_volume_status_error_extending(self, mock_sleep):
+ # Tests that the wait method raises VolumeExtendErrorException if
+ # the volume status is 'error_extending'.
+ client = mock.Mock(spec=volumes_client.VolumesClient,
+ resource_type="volume",
+ build_interval=1)
+ volume1 = {'volume': {'status': 'extending'}}
+ volume2 = {'volume': {'status': 'error_extending'}}
+ mock_show = mock.Mock(side_effect=(volume1, volume2))
+ client.show_volume = mock_show
+ volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
+ self.assertRaises(exceptions.VolumeExtendErrorException,
+ waiters.wait_for_volume_resource_status,
+ client, volume_id, 'available')
+ mock_show.assert_has_calls([mock.call(volume_id),
+ mock.call(volume_id)])
+ mock_sleep.assert_called_once_with(1)
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index 644a018..caad41c 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -106,6 +106,15 @@
self.assertEqual(self.conn.get_disks(), result)
self._assert_exec_called_with('lsblk -lb --nodeps')
+ def test_count_disk(self):
+ output_lsblk = """\
+NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
+sda 8:0 0 128035676160 0 disk
+sdb 8:16 0 1000204886016 0 disk
+sr0 11:0 1 1073741312 0 rom"""
+ self.ssh_mock.mock.exec_command.return_value = output_lsblk
+ self.assertEqual(self.conn.count_disks(), 2)
+
def test_get_boot_time(self):
booted_at = 10000
uptime_sec = 5000.02
diff --git a/tempest/tests/lib/services/identity/v3/test_application_credentials_client.py b/tempest/tests/lib/services/identity/v3/test_application_credentials_client.py
index 9bf9b68..2774c44 100644
--- a/tempest/tests/lib/services/identity/v3/test_application_credentials_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_application_credentials_client.py
@@ -146,7 +146,7 @@
def test_list_application_credential_with_bytes_body(self):
self._test_list_app_creds(bytes_body=True)
- def test_delete_trust(self):
+ def test_delete_application_credential(self):
self.check_service_client_function(
self.client.delete_application_credential,
'tempest.lib.common.rest_client.RestClient.delete',
diff --git a/tempest/tests/lib/services/identity/v3/test_users_client.py b/tempest/tests/lib/services/identity/v3/test_users_client.py
index d030c5e..c0dfdae 100644
--- a/tempest/tests/lib/services/identity/v3/test_users_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_users_client.py
@@ -25,6 +25,11 @@
'enabled': True,
'name': 'Tempest User',
'password': 'TempestPassword',
+ "description": "Tempest User",
+ "email": "TempestUser@example.com",
+ "options": {
+ "ignore_password_expiry": True
+ }
}
}
diff --git a/tempest/tests/lib/services/image/v2/test_image_members_client.py b/tempest/tests/lib/services/image/v2/test_image_members_client.py
index 703b6e1..2caa567 100644
--- a/tempest/tests/lib/services/image/v2/test_image_members_client.py
+++ b/tempest/tests/lib/services/image/v2/test_image_members_client.py
@@ -27,6 +27,28 @@
"schema": "/v2/schemas/member"
}
+ FAKE_LIST_IMAGE_MEMBERS = {
+ "members": [
+ {
+ "created_at": "2013-10-07T17:58:03Z",
+ "image_id": "dbc999e3-c52f-4200-bedd-3b18fe7f87fe",
+ "member_id": "123456789",
+ "schema": "/v2/schemas/member",
+ "status": "pending",
+ "updated_at": "2013-10-07T17:58:03Z"
+ },
+ {
+ "created_at": "2013-10-07T17:58:55Z",
+ "image_id": "dbc999e3-c52f-4200-bedd-3b18fe7f87fe",
+ "member_id": "987654321",
+ "schema": "/v2/schemas/member",
+ "status": "accepted",
+ "updated_at": "2013-10-08T12:08:55Z"
+ }
+ ],
+ "schema": "/v2/schemas/members"
+ }
+
def setUp(self):
super(TestImageMembersClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -34,6 +56,14 @@
'image',
'regionOne')
+ def _test_list_image_members(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_image_members,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_IMAGE_MEMBERS,
+ bytes_body,
+ image_id="dbc999e3-c52f-4200-bedd-3b18fe7f87fe")
+
def _test_show_image_member(self, bytes_body=False):
self.check_service_client_function(
self.client.show_image_member,
@@ -62,6 +92,12 @@
member_id="8989447062e04a818baf9e073fd04fa7",
schema="/v2/schemas/member2")
+ def test_list_image_members_with_str_body(self):
+ self._test_list_image_members()
+
+ def test_list_image_members_with_bytes_body(self):
+ self._test_list_image_members(bytes_body=True)
+
def test_show_image_member_with_str_body(self):
self._test_show_image_member()
diff --git a/tempest/tests/lib/services/image/v2/test_namespaces_client.py b/tempest/tests/lib/services/image/v2/test_namespaces_client.py
index 4cb9d01..3b057ad 100644
--- a/tempest/tests/lib/services/image/v2/test_namespaces_client.py
+++ b/tempest/tests/lib/services/image/v2/test_namespaces_client.py
@@ -26,6 +26,51 @@
"protected": True
}
+ FAKE_LIST_NAMESPACES = {
+ "first": "/v2/metadefs/namespaces?sort_key=created_at&sort_dir=asc",
+ "namespaces": [
+ {
+ "created_at": "2014-08-28T17:13:06Z",
+ "description": "OS::Compute::Libvirt",
+ "display_name": "libvirt Driver Options",
+ "namespace": "OS::Compute::Libvirt",
+ "owner": "admin",
+ "protected": True,
+ "resource_type_associations": [
+ {
+ "created_at": "2014-08-28T17:13:06Z",
+ "name": "OS::Glance::Image",
+ "updated_at": "2014-08-28T17:13:06Z"
+ }
+ ],
+ "schema": "/v2/schemas/metadefs/namespace",
+ "self": "/v2/metadefs/namespaces/OS::Compute::Libvirt",
+ "updated_at": "2014-08-28T17:13:06Z",
+ "visibility": "public"
+ },
+ {
+ "created_at": "2014-08-28T17:13:06Z",
+ "description": "OS::Compute::Quota",
+ "display_name": "Flavor Quota",
+ "namespace": "OS::Compute::Quota",
+ "owner": "admin",
+ "protected": True,
+ "resource_type_associations": [
+ {
+ "created_at": "2014-08-28T17:13:06Z",
+ "name": "OS::Nova::Flavor",
+ "updated_at": "2014-08-28T17:13:06Z"
+ }
+ ],
+ "schema": "/v2/schemas/metadefs/namespace",
+ "self": "/v2/metadefs/namespaces/OS::Compute::Quota",
+ "updated_at": "2014-08-28T17:13:06Z",
+ "visibility": "public"
+ }
+ ],
+ "schema": "/v2/schemas/metadefs/namespaces"
+ }
+
FAKE_UPDATE_NAMESPACE = {
"namespace": "OS::Compute::Hypervisor",
"visibility": "public",
@@ -48,6 +93,13 @@
bytes_body,
namespace="OS::Compute::Hypervisor")
+ def _test_list_namespaces(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_namespaces,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_NAMESPACES,
+ bytes_body)
+
def _test_create_namespace(self, bytes_body=False):
self.check_service_client_function(
self.client.create_namespace,
@@ -74,6 +126,12 @@
def test_show_namespace_with_bytes_body(self):
self._test_show_namespace(bytes_body=True)
+ def test_list_namespaces_with_str_body(self):
+ self._test_list_namespaces()
+
+ def test_list_namespaces_with_bytes_body(self):
+ self._test_list_namespaces(bytes_body=True)
+
def test_create_namespace_with_str_body(self):
self._test_create_namespace()
diff --git a/tempest/tests/lib/services/volume/v3/test_backups_client.py b/tempest/tests/lib/services/volume/v3/test_backups_client.py
index 5412064..97e1132 100644
--- a/tempest/tests/lib/services/volume/v3/test_backups_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_backups_client.py
@@ -60,8 +60,11 @@
],
"name": "backup001",
"object_count": 22,
+ "os-backup-project-attr:project_id": "2c67a14be9314c5dae2ee6",
+ "user_id": "515ba0dd59f84f25a6a084a45d8d93b2",
"size": 1,
"status": "available",
+ "updated_at": "2013-04-02T10:35:27.000000",
"volume_id": "e5185058-943a-4cb4-96d9-72c184c337d6",
"is_incremental": True,
"has_dependent_backups": False
@@ -73,7 +76,16 @@
"backup": {
"id": "4c65c15f-a5c5-464b-b92a-90e4c04636a7",
"name": "fake-backup-name",
- "links": "fake-links"
+ "links": [
+ {
+ "href": "fake-url-1",
+ "rel": "self"
+ },
+ {
+ "href": "fake-url-2",
+ "rel": "bookmark"
+ }
+ ]
}
}
diff --git a/tempest/tests/lib/services/volume/v3/test_groups_client.py b/tempest/tests/lib/services/volume/v3/test_groups_client.py
index 5a5ae88..8a2c4ea 100644
--- a/tempest/tests/lib/services/volume/v3/test_groups_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_groups_client.py
@@ -59,11 +59,11 @@
"volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"],
"status": "available",
"availability_zone": "az1",
- "created_at": "20127-06-20T03:50:07Z"
+ "created_at": "2017-06-20T03:50:07Z"
}
}
- FAKE_LIST_GROUPS = {
+ FAKE_LIST_GROUP_DETAILS = {
"groups": [
{
"id": "0e701ab8-1bec-4b9f-b026-a7ba4af13578",
@@ -100,6 +100,19 @@
]
}
+ FAKE_LIST_GROUPS = {
+ "groups": [
+ {
+ "id": "0e701ab8-1bec-4b9f-b026-a7ba4af13578",
+ "name": "group-001",
+ },
+ {
+ "id": "e479997c-650b-40a4-9dfe-77655818b0d2",
+ "name": "group-002",
+ }
+ ]
+ }
+
def setUp(self):
super(TestGroupsClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -123,13 +136,21 @@
bytes_body,
group_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+ def _test_list_group_details(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_groups,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_GROUP_DETAILS,
+ bytes_body,
+ detail=True)
+
def _test_list_groups(self, bytes_body=False):
self.check_service_client_function(
self.client.list_groups,
'tempest.lib.common.rest_client.RestClient.get',
self.FAKE_LIST_GROUPS,
bytes_body,
- detail=True)
+ detail=False)
def test_create_group_with_str_body(self):
self._test_create_group()
@@ -143,6 +164,12 @@
def test_show_group_with_bytes_body(self):
self._test_show_group(bytes_body=True)
+ def test_list_group_details_with_str_body(self):
+ self._test_list_group_details()
+
+ def test_list_group_details_with_bytes_body(self):
+ self._test_list_group_details(bytes_body=True)
+
def test_list_groups_with_str_body(self):
self._test_list_groups()
diff --git a/tempest/tests/lib/services/volume/v3/test_types_client.py b/tempest/tests/lib/services/volume/v3/test_types_client.py
index 7021a3f..336aa32 100644
--- a/tempest/tests/lib/services/volume/v3/test_types_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_types_client.py
@@ -46,10 +46,8 @@
FAKE_UPDATE_VOLUME_TYPE = {
'volume_type': {
'id': '6685584b-1eac-4da6-b5c3-555430cf68ff',
- 'qos_specs_id': None,
'name': 'volume-type-test',
'description': 'default volume type',
- 'os-volume-type-access:is_public': True,
'is_public': True,
'extra_specs': {
'volume_backend_name': 'rbd'
diff --git a/tempest/tests/lib/services/volume/v3/test_volumes_client.py b/tempest/tests/lib/services/volume/v3/test_volumes_client.py
index 1250536..56c1a35 100644
--- a/tempest/tests/lib/services/volume/v3/test_volumes_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_volumes_client.py
@@ -24,27 +24,25 @@
FAKE_VOLUME_SUMMARY = {
"volume-summary": {
- "total_size": 20,
- "total_count": 5
+ "total_size": 4,
+ "total_count": 4,
+ "metadata": {
+ "key1": ["value1", "value2"],
+ "key2": ["value2"]
+ }
}
}
FAKE_VOLUME_METADATA_ITEM = {
"meta": {
- "key1": "value1"
+ "name": "metadata1"
}
}
FAKE_VOLUME_IMAGE_METADATA = {
"metadata": {
- "container_format": "bare",
- "min_ram": "0",
- "disk_format": "raw",
- "image_name": "xly-ubuntu16-server",
- "image_id": "3e087b0c-10c5-4255-b147-6e8e9dbad6fc",
- "checksum": "008f5d22fe3cb825d714da79607a90f9",
- "min_disk": "0",
- "size": "8589934592"
+ "key1": "value1",
+ "key2": "value2"
}
}
diff --git a/tempest/tests/lib/test_base.py b/tempest/tests/lib/test_base.py
index 27cda1a..2c16e1c 100644
--- a/tempest/tests/lib/test_base.py
+++ b/tempest/tests/lib/test_base.py
@@ -48,6 +48,7 @@
@classmethod
def setUpClass(cls): # noqa
"""Simulate absence of super() call."""
+ cls.orig_skip_exception = cls.skipException
def setUp(self):
try:
diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py
index 37fe646..c849231 100644
--- a/tempest/tests/lib/test_ssh.py
+++ b/tempest/tests/lib/test_ssh.py
@@ -170,7 +170,8 @@
@mock.patch('select.POLLIN', SELECT_POLLIN, create=True)
def test_timeout_in_exec_command(self):
- chan_mock, poll_mock, _ = self._set_mocks_for_select([0, 0, 0], True)
+ chan_mock, poll_mock, _, _ = (
+ self._set_mocks_for_select([0, 0, 0], True))
# Test for a timeout condition immediately raised
client = ssh.Client('localhost', 'root', timeout=2)
@@ -187,7 +188,7 @@
@mock.patch('select.POLLIN', SELECT_POLLIN, create=True)
def test_exec_command(self):
- chan_mock, poll_mock, select_mock = (
+ chan_mock, poll_mock, select_mock, client_mock = (
self._set_mocks_for_select([[1, 0, 0]], True))
chan_mock.recv_exit_status.return_value = 0
@@ -211,6 +212,8 @@
chan_mock.recv_stderr.assert_called_once_with(1024)
chan_mock.recv_exit_status.assert_called_once_with()
+ client_mock.close.assert_called_once_with()
+
def _set_mocks_for_select(self, poll_data, ito_value=False):
gsc_mock = self.patch('tempest.lib.common.ssh.Client.'
'_get_ssh_connection')
@@ -235,14 +238,15 @@
else:
poll_mock.poll.return_value = poll_data
- return chan_mock, poll_mock, select_mock
+ return chan_mock, poll_mock, select_mock, client_mock
_utf8_string = six.unichr(1071)
_utf8_bytes = _utf8_string.encode("utf-8")
@mock.patch('select.POLLIN', SELECT_POLLIN, create=True)
def test_exec_good_command_output(self):
- chan_mock, poll_mock, _ = self._set_mocks_for_select([1, 0, 0])
+ chan_mock, poll_mock, _, _ = (
+ self._set_mocks_for_select([1, 0, 0]))
closed_prop = mock.PropertyMock(return_value=True)
type(chan_mock).closed = closed_prop
@@ -257,7 +261,8 @@
@mock.patch('select.POLLIN', SELECT_POLLIN, create=True)
def test_exec_bad_command_output(self):
- chan_mock, poll_mock, _ = self._set_mocks_for_select([1, 0, 0])
+ chan_mock, poll_mock, _, _ = (
+ self._set_mocks_for_select([1, 0, 0]))
closed_prop = mock.PropertyMock(return_value=True)
type(chan_mock).closed = closed_prop
diff --git a/tempest/tests/test_test.py b/tempest/tests/test_test.py
index a2e0efd..49fd010 100644
--- a/tempest/tests/test_test.py
+++ b/tempest/tests/test_test.py
@@ -531,8 +531,8 @@
def test_skip_only(self):
# If a skip condition is hit in the test, no credentials or resource
# is provisioned / cleaned-up
- exc, _ = test.BaseTestCase.handle_skip_exception()
- self.mocks['skip_checks'].side_effect = (exc)
+ self.mocks['skip_checks'].side_effect = (
+ testtools.TestCase.skipException())
suite = unittest.TestSuite((self.test,))
log = []
result = LoggingTestResult(log)
diff --git a/tools/tempest-integrated-gate-networking-blacklist.txt b/tools/tempest-integrated-gate-networking-blacklist.txt
index 9566f69..263b2e4 100644
--- a/tools/tempest-integrated-gate-networking-blacklist.txt
+++ b/tools/tempest-integrated-gate-networking-blacklist.txt
@@ -3,7 +3,9 @@
# Skip Cinder, Glance, keystone and Swift API tests.
tempest.api.volume
+tempest.api.compute.volumes
tempest.api.image
+tempest.api.compute.images
tempest.api.object_storage
tempest.api.identity
diff --git a/tools/tempest-plugin-sanity.sh b/tools/tempest-plugin-sanity.sh
index a087a4c..b484a41 100644
--- a/tools/tempest-plugin-sanity.sh
+++ b/tools/tempest-plugin-sanity.sh
@@ -60,6 +60,9 @@
fi
}
+: ${UPPER_CONSTRAINTS_FILE:="https://releases.openstack.org/constraints/upper/master"}
+DEPS="-c${UPPER_CONSTRAINTS_FILE}"
+
# function to create virtualenv to perform sanity operation
function prepare_workspace {
SANITY_DIR=$(pwd)
@@ -73,10 +76,10 @@
# Function to install project
function install_project {
- "$TVENV" pip install "$SANITY_DIR"/"$1"
+ "$TVENV" pip install $DEPS "$SANITY_DIR"/"$1"
# Check for test-requirements.txt file in a project then install it.
if [ -e "$SANITY_DIR"/"$1"/test-requirements.txt ]; then
- "$TVENV" pip install -r "$SANITY_DIR"/"$1"/test-requirements.txt
+ "$TVENV" pip install $DEPS -r "$SANITY_DIR"/"$1"/test-requirements.txt
fi
}