Merge "Convert job legacy-periodic-tempest-dsvm-all-master"
diff --git a/.zuul.yaml b/.zuul.yaml
index 5b745ad..c5f7ecc 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -343,6 +343,17 @@
devstack_localrc:
TEMPEST_HAS_ADMIN: False
+- job:
+ name: tempest-pg-full
+ parent: tempest-full
+ description: |
+ Base integration test with Neutron networking and py27 and PostgreSQL.
+ Former name for this job was legacy-tempest-dsvm-neutron-pg-full.
+ vars:
+ devstack_localrc:
+ ENABLE_FILE_INJECTION: true
+ DATABASE_TYPE: postgresql
+
- project:
templates:
- check-requirements
@@ -460,7 +471,7 @@
irrelevant-files: *tempest-irrelevant-files
- devstack-plugin-ceph-tempest-py3:
irrelevant-files: *tempest-irrelevant-files
- - legacy-tempest-dsvm-neutron-pg-full:
+ - tempest-pg-full:
irrelevant-files: *tempest-irrelevant-files
- tempest-full-py3-opensuse150:
irrelevant-files: *tempest-irrelevant-files
diff --git a/releasenotes/notes/add-redirect-param-bea1f6fbce629c70.yaml b/releasenotes/notes/add-redirect-param-bea1f6fbce629c70.yaml
new file mode 100644
index 0000000..f245dcb
--- /dev/null
+++ b/releasenotes/notes/add-redirect-param-bea1f6fbce629c70.yaml
@@ -0,0 +1,16 @@
+---
+features:
+ - |
+ A new parameter ``follow_redirects`` has been added to the class
+ ``RestClient``, which is passed through to ``ClosingHttp`` or
+ ``ClosingProxyHttp`` respectively. The default value is ``True``
+ which corresponds to the previous behaviour of following up to five
+ redirections before returning a response. Setting
+ ``follow_redirects = False`` allows to disable this behaviour, so
+ that any redirect that is received is directly returned to the caller.
+ This allows tests to verify that an API is responding with a redirect.
+fixes:
+ - |
+ [`bug 1616892 <https://bugs.launchpad.net/tempest/+bug/1616892>`_]
+ Tempest now allows tests to verify that an API responds with a
+ redirect.
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 1e952a1..2a5d607 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -20,10 +20,10 @@
from tempest.api.compute import base
from tempest.common import compute
from tempest.common import utils
-from tempest.common.utils.linux import remote_client
from tempest.common.utils import net_utils
from tempest.common import waiters
from tempest import config
+from tempest.lib.common.utils.linux import remote_client
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py
index 148b368..50f3186 100644
--- a/tempest/api/identity/admin/v3/test_list_projects.py
+++ b/tempest/api/identity/admin/v3/test_list_projects.py
@@ -14,9 +14,12 @@
# under the License.
from tempest.api.identity import base
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+CONF = config.CONF
+
class BaseListProjectsTestJSON(base.BaseIdentityV3AdminTest):
@@ -60,34 +63,12 @@
cls.p3['id'])
cls.project_ids.append(cls.p3['id'])
- @decorators.idempotent_id('1d830662-22ad-427c-8c3e-4ec854b0af44')
- def test_list_projects(self):
- # List projects
- list_projects = self.projects_client.list_projects()['projects']
-
- for p in self.project_ids:
- show_project = self.projects_client.show_project(p)['project']
- self.assertIn(show_project, list_projects)
-
- @decorators.idempotent_id('fab13f3c-f6a6-4b9f-829b-d32fd44fdf10')
- def test_list_projects_with_domains(self):
- # List projects with domain
- self._list_projects_with_params(
- [self.p1], [self.p2, self.p3], {'domain_id': self.domain['id']},
- 'domain_id')
-
@decorators.idempotent_id('0fe7a334-675a-4509-b00e-1c4b95d5dae8')
def test_list_projects_with_enabled(self):
# List the projects with enabled
self._list_projects_with_params(
[self.p1], [self.p2, self.p3], {'enabled': False}, 'enabled')
- @decorators.idempotent_id('fa178524-4e6d-4925-907c-7ab9f42c7e26')
- def test_list_projects_with_name(self):
- # List projects with name
- self._list_projects_with_params(
- [self.p1], [self.p2, self.p3], {'name': self.p1_name}, 'name')
-
@decorators.idempotent_id('6edc66f5-2941-4a17-9526-4073311c1fac')
def test_list_projects_with_parent(self):
# List projects with parent
@@ -97,3 +78,51 @@
self.assertNotEmpty(fetched_projects)
for project in fetched_projects:
self.assertEqual(self.p3['parent_id'], project['parent_id'])
+
+
+class ListProjectsStaticTestJSON(BaseListProjectsTestJSON):
+ # NOTE: force_tenant_isolation is true in the base class by default but
+ # overridden to false here to allow test execution for clouds using the
+ # pre-provisioned credentials provider.
+ force_tenant_isolation = False
+
+ @classmethod
+ def resource_setup(cls):
+ super(ListProjectsStaticTestJSON, cls).resource_setup()
+ cls.domain_id = CONF.identity.default_domain_id
+ cls.project_ids = list()
+ cls.p1_name = cls.os_primary.credentials.project_name
+ cls.p1 = cls.projects_client.show_project(
+ cls.os_primary.credentials.project_id)['project']
+ cls.project_ids.append(cls.p1['id'])
+ p2_name = data_utils.rand_name('project')
+ cls.p2 = cls.projects_client.create_project(
+ p2_name, domain_id=cls.domain_id)['project']
+ cls.addClassResourceCleanup(cls.projects_client.delete_project,
+ cls.p2['id'])
+ cls.project_ids.append(cls.p2['id'])
+
+ @decorators.idempotent_id('1d830662-22ad-427c-8c3e-4ec854b0af44')
+ def test_list_projects(self):
+ # List projects
+ list_projects = self.projects_client.list_projects()['projects']
+
+ for p in self.project_ids:
+ show_project = self.projects_client.show_project(p)['project']
+ self.assertIn(show_project, list_projects)
+
+ @decorators.idempotent_id('fa178524-4e6d-4925-907c-7ab9f42c7e26')
+ def test_list_projects_with_name(self):
+ # List projects with name
+ self._list_projects_with_params(
+ [self.p1], [self.p2], {'name': self.p1_name}, 'name')
+
+ @decorators.idempotent_id('fab13f3c-f6a6-4b9f-829b-d32fd44fdf10')
+ def test_list_projects_with_domains(self):
+ # List projects with domain
+ key = 'domain_id'
+ params = {key: self.domain_id}
+ # Verify both projects are in the self.domain_id which is the default
+ # domain
+ self._list_projects_with_params(
+ [self.p1, self.p2], [], params, key)
diff --git a/tempest/lib/common/http.py b/tempest/lib/common/http.py
index 738c37f..8c1a802 100644
--- a/tempest/lib/common/http.py
+++ b/tempest/lib/common/http.py
@@ -19,7 +19,8 @@
class ClosingProxyHttp(urllib3.ProxyManager):
def __init__(self, proxy_url, disable_ssl_certificate_validation=False,
- ca_certs=None, timeout=None):
+ ca_certs=None, timeout=None, follow_redirects=True):
+ self.follow_redirects = follow_redirects
kwargs = {}
if disable_ssl_certificate_validation:
@@ -50,9 +51,14 @@
new_headers = dict(original_headers, connection='close')
new_kwargs = dict(kwargs, headers=new_headers)
- # Follow up to 5 redirections. Don't raise an exception if
- # it's exceeded but return the HTTP 3XX response instead.
- retry = urllib3.util.Retry(raise_on_redirect=False, redirect=5)
+ if self.follow_redirects:
+ # Follow up to 5 redirections. Don't raise an exception if
+ # it's exceeded but return the HTTP 3XX response instead.
+ retry = urllib3.util.Retry(raise_on_redirect=False, redirect=5)
+ else:
+ # Do not follow redirections. Don't raise an exception if
+ # a redirect is found, but return the HTTP 3XX response instead.
+ retry = urllib3.util.Retry(redirect=False)
r = super(ClosingProxyHttp, self).request(method, url, retries=retry,
*args, **new_kwargs)
return Response(r), r.data
@@ -60,7 +66,8 @@
class ClosingHttp(urllib3.poolmanager.PoolManager):
def __init__(self, disable_ssl_certificate_validation=False,
- ca_certs=None, timeout=None):
+ ca_certs=None, timeout=None, follow_redirects=True):
+ self.follow_redirects = follow_redirects
kwargs = {}
if disable_ssl_certificate_validation:
@@ -93,9 +100,14 @@
new_headers = dict(original_headers, connection='close')
new_kwargs = dict(kwargs, headers=new_headers)
- # Follow up to 5 redirections. Don't raise an exception if
- # it's exceeded but return the HTTP 3XX response instead.
- retry = urllib3.util.Retry(raise_on_redirect=False, redirect=5)
+ if self.follow_redirects:
+ # Follow up to 5 redirections. Don't raise an exception if
+ # it's exceeded but return the HTTP 3XX response instead.
+ retry = urllib3.util.Retry(raise_on_redirect=False, redirect=5)
+ else:
+ # Do not follow redirections. Don't raise an exception if
+ # a redirect is found, but return the HTTP 3XX response instead.
+ retry = urllib3.util.Retry(redirect=False)
r = super(ClosingHttp, self).request(method, url, retries=retry,
*args, **new_kwargs)
return Response(r), r.data
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index e2fd722..ec46caf 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -70,6 +70,7 @@
:param str http_timeout: Timeout in seconds to wait for the http request to
return
:param str proxy_url: http proxy url to use.
+ :param bool follow_redirects: Set to false to stop following redirects.
"""
# The version of the API this client implements
@@ -82,7 +83,7 @@
build_interval=1, build_timeout=60,
disable_ssl_certificate_validation=False, ca_certs=None,
trace_requests='', name=None, http_timeout=None,
- proxy_url=None):
+ proxy_url=None, follow_redirects=True):
self.auth_provider = auth_provider
self.service = service
self.region = region
@@ -107,11 +108,11 @@
self.http_obj = http.ClosingProxyHttp(
proxy_url,
disable_ssl_certificate_validation=dscv, ca_certs=ca_certs,
- timeout=http_timeout)
+ timeout=http_timeout, follow_redirects=follow_redirects)
else:
self.http_obj = http.ClosingHttp(
disable_ssl_certificate_validation=dscv, ca_certs=ca_certs,
- timeout=http_timeout)
+ timeout=http_timeout, follow_redirects=follow_redirects)
def get_headers(self, accept_type=None, send_type=None):
"""Return the default headers which will be used with outgoing requests
diff --git a/tempest/tests/lib/common/test_http.py b/tempest/tests/lib/common/test_http.py
index 02436e0..336ef4a 100644
--- a/tempest/tests/lib/common/test_http.py
+++ b/tempest/tests/lib/common/test_http.py
@@ -167,3 +167,30 @@
'%s://%s:%i' % (proxy.scheme,
proxy.host,
proxy.port))
+
+
+class TestClosingHttpRedirects(base.TestCase):
+ def setUp(self):
+ super(TestClosingHttpRedirects, self).setUp()
+
+ def test_redirect_default(self):
+ connection = http.ClosingHttp()
+ self.assertTrue(connection.follow_redirects)
+
+ def test_redirect_off(self):
+ connection = http.ClosingHttp(follow_redirects=False)
+ self.assertFalse(connection.follow_redirects)
+
+
+class TestClosingProxyHttpRedirects(base.TestCase):
+ def setUp(self):
+ super(TestClosingProxyHttpRedirects, self).setUp()
+
+ def test_redirect_default(self):
+ connection = http.ClosingProxyHttp(proxy_url=PROXY_URL)
+ self.assertTrue(connection.follow_redirects)
+
+ def test_redirect_off(self):
+ connection = http.ClosingProxyHttp(follow_redirects=False,
+ proxy_url=PROXY_URL)
+ self.assertFalse(connection.follow_redirects)