Switch integration tests to run with python3

tox env for the integration tests is now renamed to 'integration'
as it is no longer run under python 2.7.

__hash__() method is now defined in integration_tests.helpers.BaseTestCase
to avoid unhashable error during loading django test runner. This is
originally caused by the fact that the base testcase class for integration
tests is implemented on top of testtools and testtools does not define
__hash__() method. In Python 3, __hash__() method must be defined
if a class (re)defines __eq__() method to make the class hashable [1].
Ideally integration base TestCase class can be implemented on top of
Django test case, but the current implementation depends on features
from testtools a lot, so it seems better to add __hash__() method
as a workaround.

Unbound methods don't exist in Python 3[2], so six.create_unbound_method
doesn' work as expected. To dynamic method generation we have to use new
descriptors interface [3] or just generate new
functools.partialmethod [4] function introduced in Python 3.4 to
generate class methods with pre-defined 'path' argument and pass 'self'
as a first function argument for class instance.

[1] https://docs.python.org/3.5/reference/datamodel.html#object.__hash__
[2] https://six.readthedocs.io/#six.create_unbound_method
[3] https://docs.python.org/3/howto/descriptor.html
[4] https://docs.python.org/3/library/functools.html#functools.partialmethod

Change-Id: I5c3078bdc66e33fe676d431bb28d92b35faaf479
This commit is contained in:
Ivan Kolodyazhny 2019-02-01 15:26:37 +02:00
parent 8bc497a5e3
commit 43f8c3b1f5
4 changed files with 19 additions and 5 deletions

View File

@ -39,7 +39,7 @@
vars: vars:
devstack_services: devstack_services:
horizon: true horizon: true
tox_envlist: py27integration tox_envlist: integration
- job: - job:
name: horizon-dsvm-tempest-plugin name: horizon-dsvm-tempest-plugin

View File

@ -200,6 +200,9 @@ class BaseTestCase(testtools.TestCase):
super(BaseTestCase, self).addOnException(wrapped_handler) super(BaseTestCase, self).addOnException(wrapped_handler)
def __hash__(self):
return hash((type(self), self._testMethodName))
def _configure_log(self): def _configure_log(self):
"""Configure log to capture test logs include selenium logs. """Configure log to capture test logs include selenium logs.

View File

@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import functools
import importlib import importlib
import json import json
@ -316,6 +317,16 @@ class Navigation(object):
def _create_go_to_method(cls, path, class_name=None): def _create_go_to_method(cls, path, class_name=None):
go_to_method = Navigation.GoToMethodFactory(path, class_name) go_to_method = Navigation.GoToMethodFactory(path, class_name)
inst_method = six.create_unbound_method(go_to_method, Navigation) inst_method = six.create_unbound_method(go_to_method, Navigation)
# TODO(e0ne): remove python2 support once all integration jobs
# will be switched to python3.
if six.PY3:
def _go_to_page(self, path):
return Navigation._go_to_page(self, path)
wrapped_go_to = functools.partialmethod(_go_to_page, path)
setattr(Navigation, inst_method.name, wrapped_go_to)
else:
setattr(Navigation, inst_method.name, inst_method) setattr(Navigation, inst_method.name, inst_method)
@classmethod @classmethod

View File

@ -107,15 +107,15 @@ setenv =
SKIP_UNITTESTS=1 SKIP_UNITTESTS=1
commands = {[unit_tests]commands} commands = {[unit_tests]commands}
[testenv:py27integration] [testenv:integration]
envdir = {toxworkdir}/py27 basepython = python3
envdir = {toxworkdir}/venv
# Run integration tests only # Run integration tests only
passenv = AVCONV_INSTALLED passenv = AVCONV_INSTALLED
setenv = setenv =
PYTHONHASHSEED=0 PYTHONHASHSEED=0
INTEGRATION_TESTS=1 INTEGRATION_TESTS=1
SELENIUM_HEADLESS=1 SELENIUM_HEADLESS=1
basepython = python2.7
commands = {envpython} {toxinidir}/manage.py test openstack_dashboard --settings=openstack_dashboard.test.settings --verbosity 2 --tag integration {posargs} commands = {envpython} {toxinidir}/manage.py test openstack_dashboard --settings=openstack_dashboard.test.settings --verbosity 2 --tag integration {posargs}
[testenv:npm] [testenv:npm]