Merge "Fix docs markup consistency"
diff --git a/README.rst b/README.rst
index c087f29..242f4d5 100644
--- a/README.rst
+++ b/README.rst
@@ -193,6 +193,25 @@
Alternatively, there are the py27 and py35 tox jobs which will run the unit
tests with the corresponding version of python.
+One common activity is to just run a single test, you can do this with tox
+simply by specifying to just run py27 or py35 tests against a single test::
+
+ $ tox -e py27 -- -n tempest.tests.test_microversions.TestMicroversionsTestsClass.test_config_version_none_23
+
+Or all tests in the test_microversions.py file::
+
+ $ tox -e py27 -- -n tempest.tests.test_microversions
+
+You may also use regular expressions to run any matching tests::
+
+ $ tox -e py27 -- test_microversions
+
+Additionally, when running a single test, or test-file, the ``-n/--no-discover``
+argument is no longer required, however it may perform faster if included.
+
+For more information on these options and details about stestr, please see the
+`stestr documentation <http://stestr.readthedocs.io/en/latest/MANUAL.html>`_.
+
Python 2.6
----------
diff --git a/playbooks/post-tempest.yaml b/playbooks/post-tempest.yaml
index c0b9dd4..820e4f6 100644
--- a/playbooks/post-tempest.yaml
+++ b/playbooks/post-tempest.yaml
@@ -3,12 +3,20 @@
vars:
logs_root: "{{ devstack_base_dir|default('/opt/stack') }}"
stage_dir: "{{ devstack_base_dir|default('/opt/stack') }}"
+ test_results_stage_name: 'test_results'
roles:
+ - role: process-test-results
+ test_results_dir: '{{ logs_root }}/tempest'
+ tox_envdir: tempest
+ - role: process-stackviz
- role: stage-output
zuul_copy_output:
{ '{{ logs_root }}/tempest/etc/tempest.conf': 'logs',
'{{ logs_root }}/tempest/etc/accounts.yaml': 'logs',
- '{{ logs_root }}/tempest/tempest.log': 'logs' }
+ '{{ logs_root }}/tempest/tempest.log': 'logs',
+ '{{ stage_dir }}/{{ test_results_stage_name }}.subunit': 'logs',
+ '{{ stage_dir }}/{{ test_results_stage_name }}.html': 'logs',
+ '{{ stage_dir }}/stackviz': 'logs' }
extensions_to_txt:
- conf
- log
diff --git a/releasenotes/notes/remove-deprecated-skip_unless_attr-decorator-02bde59a00328f5c.yaml b/releasenotes/notes/remove-deprecated-skip_unless_attr-decorator-02bde59a00328f5c.yaml
new file mode 100644
index 0000000..621731d
--- /dev/null
+++ b/releasenotes/notes/remove-deprecated-skip_unless_attr-decorator-02bde59a00328f5c.yaml
@@ -0,0 +1,4 @@
+---
+upgrade:
+ - |
+ Remove the deprecated decorator ``skip_unless_attr`` in lib/decorators.py.
diff --git a/requirements.txt b/requirements.txt
index 023148b..2300214 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,7 +9,7 @@
netaddr>=0.7.18 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
oslo.concurrency>=3.20.0 # Apache-2.0
-oslo.config>=4.6.0 # Apache-2.0
+oslo.config>=5.1.0 # Apache-2.0
oslo.log>=3.30.0 # Apache-2.0
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
oslo.utils>=3.31.0 # Apache-2.0
diff --git a/roles/process-stackviz/README.rst b/roles/process-stackviz/README.rst
new file mode 100644
index 0000000..b05326d
--- /dev/null
+++ b/roles/process-stackviz/README.rst
@@ -0,0 +1,22 @@
+Generate stackviz report.
+
+Generate stackviz report using subunit and dstat data, using
+the stackviz archive embedded in test images.
+
+**Role Variables**
+
+.. zuul:rolevar:: devstack_base_dir
+ :default: /opt/stack
+
+ The devstack base directory.
+
+.. zuul:rolevar:: stage_dir
+ :default: /opt/stack/logs
+
+ The stage directory where the input data can be found and
+ the output will be produced.
+
+.. zuul:rolevar:: test_results_stage_name
+ :default: test_results
+
+ The name of the subunit file to be used as input.
diff --git a/roles/process-stackviz/defaults/main.yaml b/roles/process-stackviz/defaults/main.yaml
new file mode 100644
index 0000000..b1eb8d9
--- /dev/null
+++ b/roles/process-stackviz/defaults/main.yaml
@@ -0,0 +1,3 @@
+devstack_base_dir: /opt/stack
+stage_dir: /opt/stack/
+test_results_stage_name: test_results
diff --git a/roles/process-stackviz/tasks/main.yaml b/roles/process-stackviz/tasks/main.yaml
new file mode 100644
index 0000000..09de606
--- /dev/null
+++ b/roles/process-stackviz/tasks/main.yaml
@@ -0,0 +1,63 @@
+- name: Check if stackviz archive exists
+ stat:
+ path: "/opt/cache/files/stackviz-latest.tar.gz"
+ register: stackviz_archive
+
+- debug:
+ msg: "Stackviz archive could not be found in /opt/cache/files/stackviz-latest.tar.gz"
+ when: not stackviz_archive.stat.exists
+
+- name: Check if subunit data exists
+ stat:
+ path: "{{ stage_dir }}/{{ test_results_stage_name }}.subunit"
+ register: subunit_input
+
+- debug:
+ msg: "Subunit file could not be found at {{ stage_dir }}/{{ test_results_stage_name }}.subunit"
+ when: not subunit_input.stat.exists
+
+- name: Install stackviz
+ pip:
+ name: "file://{{ stackviz_archive.stat.path }}"
+ virtualenv: /tmp/stackviz
+ extra_args: -U
+ when:
+ - stackviz_archive.stat.exists
+ - subunit_input.stat.exists
+
+- name: Deploy stackviz static html+js
+ command: cp -pR /tmp/stackviz/share/stackviz-html {{ stage_dir }}/stackviz
+ when:
+ - stackviz_archive.stat.exists
+ - subunit_input.stat.exists
+
+- name: Check if dstat data exists
+ stat:
+ path: "{{ devstack_base_dir }}/logs/dstat-csv.log"
+ register: dstat_input
+ when:
+ - stackviz_archive.stat.exists
+ - subunit_input.stat.exists
+
+- name: Run stackviz with dstat
+ shell: |
+ cat {{ subunit_input.stat.path }} | \
+ /tmp/stackviz/bin/stackviz-export \
+ --dstat "{{ devstack_base_dir }}/logs/dstat-csv.log" \
+ --env --stdin \
+ {{ stage_dir }}/stackviz/data
+ when:
+ - stackviz_archive.stat.exists
+ - subunit_input.stat.exists
+ - dstat_input.stat.exists
+
+- name: Run stackviz without dstat
+ shell: |
+ cat {{ subunit_input.stat.path }} | \
+ /tmp/stackviz/bin/stackviz-export \
+ --env --stdin \
+ {{ stage_dir }}/stackviz/data
+ when:
+ - stackviz_archive.stat.exists
+ - subunit_input.stat.exists
+ - not dstat_input.stat.exists
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 705814c..9ee8858 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -434,7 +434,7 @@
# the compute API will return a 400 response.
if volume['status'] == 'in-use':
self.servers_client.detach_volume(server['id'], volume['id'])
- except exceptions.NotFound:
+ except lib_exc.NotFound:
# Ignore 404s on detach in case the server is deleted or the volume
# is already detached.
pass
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 0248c65..0e8f681 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -78,8 +78,11 @@
return port
- def _check_interface(self, iface, port_id=None, network_id=None,
- fixed_ip=None, mac_addr=None):
+ def _check_interface(self, iface, server_id=None, port_id=None,
+ network_id=None, fixed_ip=None, mac_addr=None):
+ if server_id:
+ iface = waiters.wait_for_interface_status(
+ self.interfaces_client, server_id, iface['port_id'], 'ACTIVE')
if port_id:
self.assertEqual(iface['port_id'], port_id)
if network_id:
@@ -109,9 +112,8 @@
network_id = ifs[0]['net_id']
iface = self.interfaces_client.create_interface(
server['id'], net_id=network_id)['interfaceAttachment']
- iface = waiters.wait_for_interface_status(
- self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE')
- self._check_interface(iface, network_id=network_id)
+ self._check_interface(iface, server_id=server['id'],
+ network_id=network_id)
return iface
def _test_create_interface_by_port_id(self, server, ifs):
@@ -121,9 +123,8 @@
self.addCleanup(self.ports_client.delete_port, port_id)
iface = self.interfaces_client.create_interface(
server['id'], port_id=port_id)['interfaceAttachment']
- iface = waiters.wait_for_interface_status(
- self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE')
- self._check_interface(iface, port_id=port_id)
+ self._check_interface(iface, server_id=server['id'], port_id=port_id,
+ network_id=network_id)
return iface
def _test_create_interface_by_fixed_ips(self, server, ifs):
@@ -140,9 +141,8 @@
server['id'], net_id=network_id,
fixed_ips=fixed_ips)['interfaceAttachment']
self.addCleanup(self.ports_client.delete_port, iface['port_id'])
- iface = waiters.wait_for_interface_status(
- self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE')
- self._check_interface(iface, fixed_ip=ip_list[0])
+ self._check_interface(iface, server_id=server['id'],
+ fixed_ip=ip_list[0])
return iface
def _test_show_interface(self, server, ifs):
@@ -271,7 +271,8 @@
# attach the port to the server
iface = self.interfaces_client.create_interface(
server['id'], port_id=port_id)['interfaceAttachment']
- self._check_interface(iface, port_id=port_id)
+ self._check_interface(iface, server_id=server['id'],
+ port_id=port_id)
# detach the port from the server; this is a cast in the compute
# API so we have to poll the port until the device_id is unset.
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index bce7524..e2be249 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -326,10 +326,22 @@
server = self.create_test_server(
volume_backed=True, wait_until='ACTIVE')
self._test_resize_server_confirm(server['id'])
- # Now do something interactive with the guest like get its console
- # output; we don't actually care about the output, just that it doesn't
- # raise an error.
- self.client.get_console_output(server['id'])
+ if CONF.compute_feature_enabled.console_output:
+ # Now do something interactive with the guest like get its console
+ # output; we don't actually care about the output,
+ # just that it doesn't raise an error.
+ self.client.get_console_output(server['id'])
+ if CONF.validation.run_validation:
+ validation_resources = self.get_class_validation_resources(
+ self.os_primary)
+ linux_client = remote_client.RemoteClient(
+ self.get_server_ip(server, validation_resources),
+ self.ssh_user,
+ password=None,
+ pkey=validation_resources['keypair']['private_key'],
+ server=server,
+ servers_client=self.client)
+ linux_client.validate_authentication()
@decorators.idempotent_id('138b131d-66df-48c9-a171-64f45eb92962')
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py
index 25dd52b..82664e8 100644
--- a/tempest/api/identity/admin/v3/test_list_projects.py
+++ b/tempest/api/identity/admin/v3/test_list_projects.py
@@ -27,32 +27,27 @@
# Create a domain
cls.domain = cls.create_domain()
# Create project with domain
- cls.projects = list()
cls.p1_name = data_utils.rand_name('project')
cls.p1 = cls.projects_client.create_project(
cls.p1_name, enabled=False,
domain_id=cls.domain['id'])['project']
- cls.projects.append(cls.p1)
+ cls.addClassResourceCleanup(cls.projects_client.delete_project,
+ cls.p1['id'])
cls.project_ids.append(cls.p1['id'])
# Create default project
p2_name = data_utils.rand_name('project')
cls.p2 = cls.projects_client.create_project(p2_name)['project']
- cls.projects.append(cls.p2)
+ cls.addClassResourceCleanup(cls.projects_client.delete_project,
+ cls.p2['id'])
cls.project_ids.append(cls.p2['id'])
# Create a new project (p3) using p2 as parent project
p3_name = data_utils.rand_name('project')
cls.p3 = cls.projects_client.create_project(
p3_name, parent_id=cls.p2['id'])['project']
- cls.projects.append(cls.p3)
+ cls.addClassResourceCleanup(cls.projects_client.delete_project,
+ cls.p3['id'])
cls.project_ids.append(cls.p3['id'])
- @classmethod
- def resource_cleanup(cls):
- # Cleanup the projects created during setup in inverse order
- for project in reversed(cls.projects):
- cls.projects_client.delete_project(project['id'])
- super(ListProjectsTestJSON, cls).resource_cleanup()
-
@decorators.idempotent_id('1d830662-22ad-427c-8c3e-4ec854b0af44')
def test_list_projects(self):
# List projects
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index c2a67e3..bdfda0a 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -92,7 +92,6 @@
cls.subnets = []
cls.ports = []
cls.routers = []
- cls.floating_ips = []
cls.ethertype = "IPv" + str(cls._ip_version)
if cls._ip_version == 4:
cls.cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
@@ -104,11 +103,6 @@
@classmethod
def resource_cleanup(cls):
if CONF.service_available.neutron:
- # Clean up floating IPs
- for floating_ip in cls.floating_ips:
- test_utils.call_and_ignore_notfound_exc(
- cls.floating_ips_client.delete_floatingip,
- floating_ip['id'])
# Clean up ports
for port in cls.ports:
test_utils.call_and_ignore_notfound_exc(
@@ -222,7 +216,9 @@
body = cls.floating_ips_client.create_floatingip(
floating_network_id=external_network_id)
fip = body['floatingip']
- cls.floating_ips.append(fip)
+ cls.addClassResourceCleanup(test_utils.call_and_ignore_notfound_exc,
+ cls.floating_ips_client.delete_floatingip,
+ fip['id'])
return fip
@classmethod
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index de28a30..b73bdf2 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -18,6 +18,7 @@
import testtools
from tempest.api.volume import base
+from tempest.common import utils
from tempest.common import waiters
from tempest import config
from tempest.lib import decorators
@@ -104,6 +105,7 @@
@decorators.idempotent_id('301f5a30-1c6f-4ea0-be1a-91fd28d44354')
@testtools.skipUnless(CONF.volume_feature_enabled.extend_attached_volume,
"Attached volume extend is disabled.")
+ @utils.services('compute')
def test_extend_attached_volume(self):
"""This is a happy path test which does the following:
diff --git a/tempest/common/utils/__init__.py b/tempest/common/utils/__init__.py
index 5a86caa..aa81864 100644
--- a/tempest/common/utils/__init__.py
+++ b/tempest/common/utils/__init__.py
@@ -78,7 +78,7 @@
decorators.attr(type=list(args))(f)
@functools.wraps(f)
- def wrapper(self, *func_args, **func_kwargs):
+ def wrapper(*func_args, **func_kwargs):
service_list = get_service_list()
for service in args:
@@ -86,7 +86,7 @@
msg = 'Skipped because the %s service is not available' % (
service)
raise testtools.TestCase.skipException(msg)
- return f(self, *func_args, **func_kwargs)
+ return f(*func_args, **func_kwargs)
return wrapper
return decorator
diff --git a/tempest/lib/decorators.py b/tempest/lib/decorators.py
index ef1003b..e99dd24 100644
--- a/tempest/lib/decorators.py
+++ b/tempest/lib/decorators.py
@@ -15,7 +15,6 @@
import functools
import uuid
-import debtcollector.removals
from oslo_log import log as logging
import six
import testtools
@@ -56,9 +55,9 @@
"""
def decorator(f):
@functools.wraps(f)
- def wrapper(self, *func_args, **func_kwargs):
+ def wrapper(*func_args, **func_kwargs):
try:
- return f(self, *func_args, **func_kwargs)
+ return f(*func_args, **func_kwargs)
except Exception as exc:
exc_status_code = getattr(exc, 'status_code', None)
if status_code is None or status_code == exc_status_code:
@@ -87,25 +86,6 @@
return decorator
-@debtcollector.removals.remove(removal_version='Queen')
-class skip_unless_attr(object):
- """Decorator to skip tests if a specified attr does not exists or False"""
- def __init__(self, attr, msg=None):
- self.attr = attr
- self.message = msg or ("Test case attribute %s not found "
- "or False") % attr
-
- def __call__(self, func):
- @functools.wraps(func)
- def _skipper(*args, **kw):
- """Wrapped skipper function."""
- testobj = args[0]
- if not getattr(testobj, self.attr, False):
- raise testtools.TestCase.skipException(self.message)
- func(*args, **kw)
- return _skipper
-
-
def attr(**kwargs):
"""A decorator which applies the testtools attr decorator
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index 9b2e87e..13af890 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -96,7 +96,7 @@
class Conflict(ClientRestClientException):
status_code = 409
- message = "An object with that identifier already exists"
+ message = "Conflict with state of target resource"
class Gone(ClientRestClientException):
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 6332c6d..ff8837f 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -421,6 +421,10 @@
def test_mtu_sized_frames(self):
"""Validate that network MTU sized frames fit through."""
self._setup_network_and_servers()
+ # first check that connectivity works in general for the instance
+ self.check_public_network_connectivity(should_connect=True)
+ # now that we checked general connectivity, test that full size frames
+ # can also pass between nodes
self.check_public_network_connectivity(
should_connect=True, mtu=self.network['mtu'])
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 64ea8f6..beb039c 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -208,7 +208,19 @@
# boot instance from EBS image
instance = self.create_server(image_id=image['id'])
- # just ensure that instance booted
+
+ # Verify the server was created from the image
+ created_volume = instance['os-extended-volumes:volumes_attached']
+ self.assertNotEmpty(created_volume, "No volume attachment found.")
+ created_volume_info = self.volumes_client.show_volume(
+ created_volume[0]['id'])['volume']
+ self.assertEqual(instance['id'],
+ created_volume_info['attachments'][0]['server_id'])
+ self.assertEqual(created_volume[0]['id'],
+ created_volume_info['attachments'][0]['volume_id'])
+ self.assertEqual(
+ volume_origin['volume_image_metadata']['image_id'],
+ created_volume_info['volume_image_metadata']['image_id'])
# delete instance
self._delete_server(instance)
diff --git a/tempest/tests/lib/services/network/test_networks_client.py b/tempest/tests/lib/services/network/test_networks_client.py
new file mode 100644
index 0000000..078f4b0
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_networks_client.py
@@ -0,0 +1,242 @@
+# Copyright 2017 AT&T 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 copy
+
+from tempest.lib.services.network import networks_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestNetworksClient(base.BaseServiceTest):
+
+ FAKE_NETWORKS = {
+ "networks": [
+ {
+ "admin_state_up": True,
+ "availability_zone_hints": [],
+ "availability_zones": [
+ "nova"
+ ],
+ "created_at": "2016-03-08T20:19:41",
+ "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "mtu": 0,
+ "name": "net1",
+ "port_security_enabled": True,
+ "project_id": "4fd44f30292945e481c7b8a0c8908869",
+ "qos_policy_id": "6a8454ade84346f59e8d40665f878b2e",
+ "router:external": False,
+ "shared": False,
+ "status": "ACTIVE",
+ "subnets": [
+ "54d6f61d-db07-451c-9ab3-b9609b6b6f0b"
+ ],
+ "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+ "updated_at": "2016-03-08T20:19:41",
+ "vlan_transparent": True,
+ "description": ""
+ },
+ {
+ "admin_state_up": True,
+ "availability_zone_hints": [],
+ "availability_zones": [
+ "nova"
+ ],
+ "id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+ "mtu": 0,
+ "name": "net2",
+ "port_security_enabled": True,
+ "project_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+ "qos_policy_id": "bfdb6c39f71e4d44b1dfbda245c50819",
+ "router:external": False,
+ "shared": False,
+ "status": "ACTIVE",
+ "subnets": [
+ "08eae331-0402-425a-923c-34f7cfe39c1b"
+ ],
+ "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+ "updated_at": "2016-03-08T20:19:41",
+ "vlan_transparent": False,
+ "description": ""
+ }
+ ]
+ }
+
+ FAKE_NETWORK_ID = "d32019d3-bc6e-4319-9c1d-6722fc136a22"
+
+ FAKE_NETWORK1 = {
+ "name": "net1",
+ "admin_state_up": True,
+ "qos_policy_id": "6a8454ade84346f59e8d40665f878b2e"
+ }
+
+ FAKE_NETWORK2 = {
+ "name": "net2",
+ "admin_state_up": True,
+ "qos_policy_id": "bfdb6c39f71e4d44b1dfbda245c50819"
+ }
+
+ FAKE_NETWORKS_REQ = {
+ "networks": [
+ FAKE_NETWORK1,
+ FAKE_NETWORK2
+ ]
+ }
+
+ FAKE_DHCP_AGENT_NETWORK_ID = "80515c45-651f-4f9a-b82b-2ca8a7301a8d"
+
+ FAKE_DHCP_AGENTS = {
+ "agents": [
+ {
+ "binary": "neutron-dhcp-agent",
+ "description": None,
+ "admin_state_up": True,
+ "heartbeat_timestamp": "2017-06-22 18:29:50",
+ "availability_zone": "nova",
+ "alive": True,
+ "topic": "dhcp_agent",
+ "host": "osboxes",
+ "agent_type": "DHCP agent",
+ "resource_versions": {},
+ "created_at": "2017-06-19 21:39:51",
+ "started_at": "2017-06-19 21:39:51",
+ "id": "b6cfb7a1-6ac4-4980-993c-9d295d37062e",
+ "configurations": {
+ "subnets": 2,
+ "dhcp_lease_duration": 86400,
+ "dhcp_driver": "neutron.agent.linux.dhcp.Dnsmasq",
+ "networks": 1,
+ "log_agent_heartbeats": False,
+ "ports": 3
+ }
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestNetworksClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.networks_client = networks_client.NetworksClient(
+ fake_auth, "network", "regionOne")
+
+ def _test_list_networks(self, bytes_body=False):
+ self.check_service_client_function(
+ self.networks_client.list_networks,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_NETWORKS,
+ bytes_body,
+ 200)
+
+ def _test_create_network(self, bytes_body=False):
+ self.check_service_client_function(
+ self.networks_client.create_network,
+ "tempest.lib.common.rest_client.RestClient.post",
+ {"network": self.FAKE_NETWORKS["networks"][0]},
+ bytes_body,
+ 201,
+ **self.FAKE_NETWORK1)
+
+ def _test_create_bulk_networks(self, bytes_body=False):
+ self.check_service_client_function(
+ self.networks_client.create_bulk_networks,
+ "tempest.lib.common.rest_client.RestClient.post",
+ self.FAKE_NETWORKS,
+ bytes_body,
+ 201,
+ networks=self.FAKE_NETWORKS_REQ)
+
+ def _test_show_network(self, bytes_body=False):
+ self.check_service_client_function(
+ self.networks_client.show_network,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"network": self.FAKE_NETWORKS["networks"][0]},
+ bytes_body,
+ 200,
+ network_id=self.FAKE_NETWORK_ID)
+
+ def _test_update_network(self, bytes_body=False):
+ update_kwargs = {
+ "name": "sample_network_5_updated",
+ "qos_policy_id": "6a8454ade84346f59e8d40665f878b2e"
+ }
+
+ resp_body = {
+ "network": copy.deepcopy(
+ self.FAKE_NETWORKS["networks"][0]
+ )
+ }
+ resp_body["network"].update(update_kwargs)
+
+ self.check_service_client_function(
+ self.networks_client.update_network,
+ "tempest.lib.common.rest_client.RestClient.put",
+ resp_body,
+ bytes_body,
+ 200,
+ network_id=self.FAKE_NETWORK_ID,
+ **update_kwargs)
+
+ def _test_list_dhcp_agents_on_hosting_network(self, bytes_body=False):
+ self.check_service_client_function(
+ self.networks_client.list_dhcp_agents_on_hosting_network,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_DHCP_AGENTS,
+ bytes_body,
+ 200,
+ network_id=self.FAKE_DHCP_AGENT_NETWORK_ID)
+
+ def test_delete_network(self):
+ self.check_service_client_function(
+ self.networks_client.delete_network,
+ "tempest.lib.common.rest_client.RestClient.delete",
+ {},
+ status=204,
+ network_id=self.FAKE_NETWORK_ID)
+
+ def test_list_networks_with_str_body(self):
+ self._test_list_networks()
+
+ def test_list_networks_with_bytes_body(self):
+ self._test_list_networks(bytes_body=True)
+
+ def test_create_network_with_str_body(self):
+ self._test_create_network()
+
+ def test_create_network_with_bytes_body(self):
+ self._test_create_network(bytes_body=True)
+
+ def test_create_bulk_network_with_str_body(self):
+ self._test_create_bulk_networks()
+
+ def test_create_bulk_network_with_bytes_body(self):
+ self._test_create_bulk_networks(bytes_body=True)
+
+ def test_show_network_with_str_body(self):
+ self._test_show_network()
+
+ def test_show_network_with_bytes_body(self):
+ self._test_show_network(bytes_body=True)
+
+ def test_update_network_with_str_body(self):
+ self._test_update_network()
+
+ def test_update_network_with_bytes_body(self):
+ self._test_update_network(bytes_body=True)
+
+ def test_list_dhcp_agents_on_hosting_network_with_str_body(self):
+ self._test_list_dhcp_agents_on_hosting_network()
+
+ def test_list_dhcp_agents_on_hosting_network_with_bytes_body(self):
+ self._test_list_dhcp_agents_on_hosting_network(bytes_body=True)
diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py
index bbebcd3..ed0eea3 100644
--- a/tempest/tests/lib/test_decorators.py
+++ b/tempest/tests/lib/test_decorators.py
@@ -125,35 +125,6 @@
self.assertRaises(ValueError, self._test_helper, _id)
-class TestSkipUnlessAttrDecorator(base.TestCase):
- def _test_skip_unless_attr(self, attr, expected_to_skip=True):
- class TestFoo(test.BaseTestCase):
- expected_attr = not expected_to_skip
-
- @decorators.skip_unless_attr(attr)
- def test_foo(self):
- pass
-
- t = TestFoo('test_foo')
- if expected_to_skip:
- self.assertRaises(testtools.TestCase.skipException,
- t.test_foo)
- else:
- try:
- t.test_foo()
- except Exception:
- raise testtools.TestCase.failureException()
-
- def test_skip_attr_does_not_exist(self):
- self._test_skip_unless_attr('unexpected_attr')
-
- def test_skip_attr_false(self):
- self._test_skip_unless_attr('expected_attr')
-
- def test_no_skip_for_attr_exist_and_true(self):
- self._test_skip_unless_attr('expected_attr', expected_to_skip=False)
-
-
class TestRelatedBugDecorator(base.TestCase):
def test_relatedbug_when_no_exception(self):
f = mock.Mock()
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index 99df0d1..dd05438 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -28,12 +28,12 @@
try:
# For Python 3.0 and later
- from urllib.error import HTTPError as HTTPError
+ from urllib.error import HTTPError
import urllib.request as urllib
except ImportError:
# Fall back to Python 2's urllib2
import urllib2 as urllib
- from urllib2 import HTTPError as HTTPError
+ from urllib2 import HTTPError
url = 'https://review.openstack.org/projects/'