Merge "Cleanup and rename test_create_ebs_image_and_check_boot"
diff --git a/.zuul.yaml b/.zuul.yaml
index 4f17959..e4e95f2 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -45,6 +45,19 @@
ENABLE_FILE_INJECTION: true
- job:
+ name: tempest-full-parallel
+ parent: tempest-full
+ voting: false
+ branches:
+ - master
+ description: |
+ Base integration test with Neutron networking and py27.
+ It includes all scenarios as it was in the past.
+ This job runs all scenario tests in parallel!
+ vars:
+ tox_envlist: full-parallel
+
+- job:
name: tempest-full-py3
parent: devstack-tempest
branches:
@@ -175,6 +188,16 @@
- ^roles/
- ^.zuul.yaml$
- nova-multiattach
+ - tempest-full-parallel:
+ irrelevant-files:
+ - ^(test-|)requirements.txt$
+ - ^.*\.rst$
+ - ^doc/.*$
+ - ^etc/.*$
+ - ^releasenotes/.*$
+ - ^setup.cfg$
+ - ^tempest/hacking/.*$
+ - ^tempest/tests/.*$
- tempest-full-queens:
irrelevant-files:
- ^(test-|)requirements.txt$
@@ -209,6 +232,18 @@
gate:
jobs:
- nova-multiattach
+ experimental:
+ jobs:
+ - nova-cells-v1:
+ irrelevant-files:
+ - ^(test-|)requirements.txt$
+ - ^.*\.rst$
+ - ^doc/.*$
+ - ^etc/.*$
+ - ^releasenotes/.*$
+ - ^setup.cfg$
+ - ^tempest/hacking/.*$
+ - ^tempest/tests/.*$
periodic-stable:
jobs:
- tempest-full-queens
diff --git a/HACKING.rst b/HACKING.rst
index f961884..bb55ac5 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -363,13 +363,24 @@
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When adding tests for new features that were not in previous releases of the
-projects the new test has to be properly skipped with a feature flag. Whether
-this is just as simple as using the @utils.requires_ext() decorator to
-check if the required extension (or discoverable optional API) is enabled or
+projects the new test has to be properly skipped with a feature flag. This can
+be just as simple as using the ``@utils.requires_ext()`` or
+``testtools.skipUnless`` decorators to check if the required extension (or
+discoverable optional API) or feature is enabled or can be as difficult as
adding a new config option to the appropriate section. If there isn't a method
of selecting the new **feature** from the config file then there won't be a
-mechanism to disable the test with older stable releases and the new test won't
-be able to merge.
+mechanism to disable the test with older stable releases and the new test
+won't be able to merge.
+
+Introduction of a new feature flag requires specifying a default value for
+the corresponding config option that is appropriate in the latest OpenStack
+release. Because Tempest is branchless, the feature flag's default value will
+need to be overridden to a value that is appropriate in earlier releases
+in which the feature isn't available. In DevStack, this can be accomplished
+by modifying Tempest's `lib installation script`_ for previous branches
+(because DevStack is branched).
+
+.. _lib installation script: http://git.openstack.org/cgit/openstack-dev/devstack/tree/lib/tempest
2. Bug fix on core project needing Tempest changes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/requirements.txt b/doc/requirements.txt
index 597b54e..d959d44 100644
--- a/doc/requirements.txt
+++ b/doc/requirements.txt
@@ -3,4 +3,4 @@
# process, which may cause wedges in the gate later.
openstackdocstheme>=1.18.1 # Apache-2.0
reno>=2.5.0 # Apache-2.0
-sphinx!=1.6.6,>=1.6.2 # BSD
+sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
diff --git a/requirements.txt b/requirements.txt
index a74042f..7520d42 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,8 +7,8 @@
testtools>=2.2.0 # MIT
paramiko>=2.0.0 # LGPLv2.1+
netaddr>=0.7.18 # BSD
-oslo.concurrency>=3.25.0 # Apache-2.0
-oslo.config>=5.1.0 # Apache-2.0
+oslo.concurrency>=3.26.0 # Apache-2.0
+oslo.config>=5.2.0 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0
stestr>=1.0.0 # Apache-2.0
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index 36ff09e..a6e0efa 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -27,16 +27,17 @@
def setup_clients(cls):
super(AggregatesAdminNegativeTestJSON, cls).setup_clients()
cls.client = cls.os_admin.aggregates_client
+ cls.services_client = cls.os_admin.services_client
@classmethod
def resource_setup(cls):
super(AggregatesAdminNegativeTestJSON, cls).resource_setup()
cls.aggregate_name_prefix = 'test_aggregate'
- hosts_all = cls.os_admin.hosts_client.list_hosts()['hosts']
- hosts = ([host['host_name']
- for host in hosts_all if host['service'] == 'compute'])
- cls.host = hosts[0]
+ svc_list = cls.services_client.list_services(
+ binary='nova-compute')['services']
+ cls.hosts = [v['host'] for v in svc_list
+ if v['status'] == 'enabled' and v['state'] == 'up']
def _create_test_aggregate(self):
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
@@ -123,11 +124,9 @@
@decorators.idempotent_id('0ef07828-12b4-45ba-87cc-41425faf5711')
def test_aggregate_add_non_exist_host(self):
# Adding a non-exist host to an aggregate should raise exceptions.
- hosts_all = self.os_admin.hosts_client.list_hosts()['hosts']
- hosts = map(lambda x: x['host_name'], hosts_all)
while True:
non_exist_host = data_utils.rand_name('nonexist_host')
- if non_exist_host not in hosts:
+ if non_exist_host not in self.hosts:
break
aggregate = self._create_test_aggregate()
self.assertRaises(lib_exc.NotFound, self.client.add_host,
@@ -140,7 +139,7 @@
aggregate = self._create_test_aggregate()
self.assertRaises(lib_exc.Forbidden,
self.aggregates_client.add_host,
- aggregate['id'], host=self.host)
+ aggregate['id'], host=self.hosts[0])
@decorators.attr(type=['negative'])
@decorators.idempotent_id('19dd44e1-c435-4ee1-a402-88c4f90b5950')
@@ -148,12 +147,12 @@
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate = self._create_test_aggregate()
- self.client.add_host(aggregate['id'], host=self.host)
+ self.client.add_host(aggregate['id'], host=self.hosts[0])
self.addCleanup(self.client.remove_host, aggregate['id'],
- host=self.host)
+ host=self.hosts[0])
self.assertRaises(lib_exc.Conflict, self.client.add_host,
- aggregate['id'], host=self.host)
+ aggregate['id'], host=self.hosts[0])
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7a53af20-137a-4e44-a4ae-e19260e626d9')
@@ -162,13 +161,13 @@
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate = self._create_test_aggregate()
- self.client.add_host(aggregate['id'], host=self.host)
+ self.client.add_host(aggregate['id'], host=self.hosts[0])
self.addCleanup(self.client.remove_host, aggregate['id'],
- host=self.host)
+ host=self.hosts[0])
self.assertRaises(lib_exc.Forbidden,
self.aggregates_client.remove_host,
- aggregate['id'], host=self.host)
+ aggregate['id'], host=self.hosts[0])
@decorators.attr(type=['negative'])
@decorators.idempotent_id('95d6a6fa-8da9-4426-84d0-eec0329f2e4d')
diff --git a/tempest/api/compute/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py
index ba19937..72d09ed 100644
--- a/tempest/api/compute/admin/test_floating_ips_bulk.py
+++ b/tempest/api/compute/admin/test_floating_ips_bulk.py
@@ -31,6 +31,7 @@
API documentation - http://docs.openstack.org/api/openstack-compute/2/
content/ext-os-floating-ips-bulk.html
"""
+ max_microversion = '2.35'
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 9759be7..760e356 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -532,10 +532,10 @@
def get_host_other_than(self, server_id):
source_host = self.get_host_for_server(server_id)
- hypers = self.os_admin.hypervisor_client.list_hypervisors(
- )['hypervisors']
- hosts = [hyper['hypervisor_hostname'] for hyper in hypers
- if hyper['state'] == 'up' and hyper['status'] == 'enabled']
+ svcs = self.os_admin.services_client.list_services(
+ binary='nova-compute')['services']
+ hosts = [svc['host'] for svc in svcs
+ if svc['state'] == 'up' and svc['status'] == 'enabled']
for target_host in hosts:
if source_host != target_host:
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index b497626..1f3af5f 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -28,6 +28,7 @@
class ImagesMetadataTestJSON(base.BaseV2ComputeTest):
+ max_microversion = '2.38'
@classmethod
def skip_checks(cls):
diff --git a/tempest/api/compute/images/test_image_metadata_negative.py b/tempest/api/compute/images/test_image_metadata_negative.py
index 03d0789..407fb08 100644
--- a/tempest/api/compute/images/test_image_metadata_negative.py
+++ b/tempest/api/compute/images/test_image_metadata_negative.py
@@ -20,6 +20,7 @@
class ImagesMetadataNegativeTestJSON(base.BaseV2ComputeTest):
+ max_microversion = '2.38'
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/test_tenant_networks.py b/tempest/api/compute/test_tenant_networks.py
index b55e2c0..f4eada0 100644
--- a/tempest/api/compute/test_tenant_networks.py
+++ b/tempest/api/compute/test_tenant_networks.py
@@ -18,6 +18,7 @@
class ComputeTenantNetworksTest(base.BaseV2ComputeTest):
+ max_microversion = '2.35'
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index 54052ae..362f4cc 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -32,7 +32,7 @@
@decorators.idempotent_id('9a36df71-a257-43a5-9555-dc7c88e66e0e')
def test_volume_extend(self):
# Extend Volume Test.
- volume = self.create_volume()
+ volume = self.create_volume(image_ref=self.image_ref)
extend_size = volume['size'] + 1
self.volumes_client.extend_volume(volume['id'],
new_size=extend_size)
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index dcd3518..52114bc 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -41,16 +41,19 @@
def test_snapshot_create_delete_with_volume_in_use(self):
# Create a test instance
server = self.create_server()
- self.attach_volume(server['id'], self.volume_origin['id'])
+ # NOTE(zhufl) Here we create volume from self.image_ref for adding
+ # coverage for "creating snapshot from non-blank volume".
+ volume = self.create_volume(image_ref=self.image_ref)
+ self.attach_volume(server['id'], volume['id'])
# Snapshot a volume which attached to an instance with force=False
self.assertRaises(lib_exc.BadRequest, self.create_snapshot,
- self.volume_origin['id'], force=False)
+ volume['id'], force=False)
# Snapshot a volume attached to an instance
- snapshot1 = self.create_snapshot(self.volume_origin['id'], force=True)
- snapshot2 = self.create_snapshot(self.volume_origin['id'], force=True)
- snapshot3 = self.create_snapshot(self.volume_origin['id'], force=True)
+ snapshot1 = self.create_snapshot(volume['id'], force=True)
+ snapshot2 = self.create_snapshot(volume['id'], force=True)
+ snapshot3 = self.create_snapshot(volume['id'], force=True)
# Delete the snapshots. Some snapshot implementations can take
# different paths according to order they are deleted.
diff --git a/tempest/cmd/subunit_describe_calls.py b/tempest/cmd/subunit_describe_calls.py
index f0ade7e..a4402fe 100644
--- a/tempest/cmd/subunit_describe_calls.py
+++ b/tempest/cmd/subunit_describe_calls.py
@@ -29,6 +29,9 @@
written to. This contains more information than is present in stdout.
* ``--ports, -p``: (Optional) The path to a JSON file describing the ports
being used by different services
+* ``--verbose, -v``: (Optional) Print Request and Response Headers and Body
+ data to stdout
+
Usage
-----
@@ -262,6 +265,10 @@
"-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.")
+
def parse(stream, non_subunit_name, ports):
if ports is not None and os.path.exists(ports):
@@ -286,7 +293,7 @@
return url_parser
-def output(url_parser, output_file):
+def output(url_parser, output_file, verbose):
if output_file is not None:
with open(output_file, "w") as outfile:
outfile.write(json.dumps(url_parser.test_logs))
@@ -302,13 +309,22 @@
sys.stdout.write('\t- {0} {1} request for {2} to {3}\n'.format(
item.get('status_code'), item.get('verb'),
item.get('service'), item.get('url')))
+ if verbose:
+ sys.stdout.write('\t\t- request headers: {0}\n'.format(
+ item.get('request_headers')))
+ sys.stdout.write('\t\t- request body: {0}\n'.format(
+ item.get('request_body')))
+ sys.stdout.write('\t\t- response headers: {0}\n'.format(
+ item.get('response_headers')))
+ sys.stdout.write('\t\t- response body: {0}\n'.format(
+ item.get('response_body')))
sys.stdout.write('\n')
def entry_point():
cl_args = ArgumentParser().parse_args()
parser = parse(cl_args.subunit, cl_args.non_subunit_name, cl_args.ports)
- output(parser, cl_args.output_file)
+ output(parser, cl_args.output_file, cl_args.verbose)
if __name__ == "__main__":
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 9ff6227..b515639 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -37,7 +37,7 @@
super(TestAggregatesBasicOps, cls).setup_clients()
# Use admin client by default
cls.aggregates_client = cls.os_admin.aggregates_client
- cls.hosts_client = cls.os_admin.hosts_client
+ cls.services_client = cls.os_admin.services_client
def _create_aggregate(self, **kwargs):
aggregate = (self.aggregates_client.create_aggregate(**kwargs)
@@ -51,10 +51,10 @@
return aggregate
def _get_host_name(self):
- hosts = self.hosts_client.list_hosts()['hosts']
- self.assertNotEmpty(hosts)
- computes = [x for x in hosts if x['service'] == 'compute']
- return computes[0]['host_name']
+ svc_list = self.services_client.list_services(
+ binary='nova-compute')['services']
+ self.assertNotEmpty(svc_list)
+ return svc_list[0]['host']
def _add_host(self, aggregate_id, host):
aggregate = (self.aggregates_client.add_host(aggregate_id, host=host)
diff --git a/tempest/tests/cmd/test_subunit_describe_calls.py b/tempest/tests/cmd/test_subunit_describe_calls.py
index 5f3d770..cb34ba6 100644
--- a/tempest/tests/cmd/test_subunit_describe_calls.py
+++ b/tempest/tests/cmd/test_subunit_describe_calls.py
@@ -33,15 +33,42 @@
p.communicate()
self.assertEqual(0, p.returncode)
+ def test_verbose(self):
+ subunit_file = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)),
+ 'sample_streams/calls.subunit')
+ p = subprocess.Popen([
+ 'subunit-describe-calls', '-s', subunit_file,
+ '-v'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ stdout = p.communicate()
+ self.assertEqual(0, p.returncode)
+ self.assertIn(b'- request headers:', stdout[0])
+ self.assertIn(b'- request body:', stdout[0])
+ self.assertIn(b'- response headers:', stdout[0])
+ self.assertIn(b'- response body:', stdout[0])
+
def test_return_code_no_output(self):
subunit_file = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'sample_streams/calls.subunit')
p = subprocess.Popen([
'subunit-describe-calls', '-s', subunit_file],
- stdin=subprocess.PIPE)
- p.communicate()
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ stdout = p.communicate()
self.assertEqual(0, p.returncode)
+ self.assertIn(b'foo', stdout[0])
+ self.assertIn(b'- 200 POST request for Nova to v2.1/<id>/',
+ stdout[0])
+ self.assertIn(b'- 200 DELETE request for Nova to v2.1/<id>/',
+ stdout[0])
+ self.assertIn(b'- 200 GET request for Nova to v2.1/<id>/',
+ stdout[0])
+ self.assertIn(b'- 404 DELETE request for Nova to v2.1/<id>/',
+ stdout[0])
+ self.assertNotIn(b'- request headers:', stdout[0])
+ self.assertNotIn(b'- request body:', stdout[0])
+ self.assertNotIn(b'- response headers:', stdout[0])
+ self.assertNotIn(b'- response body:', stdout[0])
def test_parse(self):
subunit_file = os.path.join(
diff --git a/tox.ini b/tox.ini
index 9103175..da0233a 100644
--- a/tox.ini
+++ b/tox.ini
@@ -83,6 +83,16 @@
tempest run --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.api)' {posargs}
tempest run --combine --serial --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.scenario)' {posargs}
+[testenv:full-parallel]
+envdir = .tox/tempest
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
+# The regex below is used to select all tempest scenario and including the non slow api tests
+commands =
+ find . -type f -name "*.pyc" -delete
+ tempest run --regex '(^tempest\.scenario.*)|(?!.*\[.*\bslow\b.*\])(^tempest\.api)' {posargs}
+
[testenv:full-serial]
envdir = .tox/tempest
sitepackages = {[tempestenv]sitepackages}