Handle case without pytest for plugin tests

Switching the test runner to pytest in horizon assumes pytest is always
installed, but horizon test helpers are used in horizon plugin tests and
pytest is not used in horizon plugin tests. As a result, all horizon plugin
tests are now broken.

This commit considers a case where pytest does not exist.
A wrapper decorator for pytest.mark.xxxx is introduced and
it acts as a null decorator if pytest is not installed.

Change-Id: I80736b108f5ae9a36c0e756bf386468879be3293
Closes-Bug: #1873532
This commit is contained in:
Akihiro Motoki 2020-04-18 08:38:36 +09:00
parent b62c49acf5
commit 0c96dcf293
3 changed files with 24 additions and 9 deletions

View File

@ -21,6 +21,7 @@ import copy
import logging import logging
import os import os
import socket import socket
import sys
import time import time
import unittest import unittest
@ -42,8 +43,12 @@ from django.utils.encoding import force_text
from django.contrib.staticfiles.testing \ from django.contrib.staticfiles.testing \
import StaticLiveServerTestCase as LiveServerTestCase import StaticLiveServerTestCase as LiveServerTestCase
# horizon plugins does not require pytest, so we need to consider
# pytest is not installed.
try:
import pytest import pytest
except ImportError:
pass
from horizon import middleware from horizon import middleware
@ -69,6 +74,17 @@ except ImportError as e:
wsgi.WSGIRequest.__repr__ = lambda self: "<class 'django.http.HttpRequest'>" wsgi.WSGIRequest.__repr__ = lambda self: "<class 'django.http.HttpRequest'>"
def pytest_mark(name):
if 'pytest' in sys.modules:
return getattr(pytest.mark, name)
else:
# When pytest is not installed (in case of horizon plugins),
# we don't need a pytest marker, so just use a null decorator.
def wrapper(f):
return f
return wrapper
class SessionStore(SessionBase): class SessionStore(SessionBase):
"""Dict like object for simulating sessions in unittests.""" """Dict like object for simulating sessions in unittests."""
@ -221,7 +237,7 @@ class TestCase(django_test.TestCase):
", ".join(msgs)) ", ".join(msgs))
@pytest.mark.selenium @pytest_mark('selenium')
@tag('selenium') @tag('selenium')
class SeleniumTestCase(LiveServerTestCase): class SeleniumTestCase(LiveServerTestCase):
@classmethod @classmethod

View File

@ -33,7 +33,6 @@ from django.utils import http
from openstack_auth import user from openstack_auth import user
from openstack_auth import utils from openstack_auth import utils
import pytest
from requests.packages.urllib3.connection import HTTPConnection from requests.packages.urllib3.connection import HTTPConnection
from horizon import base from horizon import base
@ -472,7 +471,7 @@ class ResetImageAPIVersionMixin(object):
super(ResetImageAPIVersionMixin, self).tearDown() super(ResetImageAPIVersionMixin, self).tearDown()
@pytest.mark.selenium @horizon_helpers.pytest_mark('selenium')
@tag('selenium') @tag('selenium')
class SeleniumTestCase(horizon_helpers.SeleniumTestCase): class SeleniumTestCase(horizon_helpers.SeleniumTestCase):
@ -540,7 +539,7 @@ def my_custom_sort(flavor):
# PluginTestCase as a separate test process. Hopefully this workaround has gone # PluginTestCase as a separate test process. Hopefully this workaround has gone
# in future. For more detail, see bugs 1809983, 1866666 and # in future. For more detail, see bugs 1809983, 1866666 and
# https://review.opendev.org/#/c/627640/. # https://review.opendev.org/#/c/627640/.
@pytest.mark.plugin_test @horizon_helpers.pytest_mark('plugin_test')
@tag('plugin-test') @tag('plugin-test')
class PluginTestCase(TestCase): class PluginTestCase(TestCase):
"""Test case for testing plugin system of Horizon. """Test case for testing plugin system of Horizon.

View File

@ -23,13 +23,13 @@ import traceback
from django.test import tag from django.test import tag
from oslo_utils import uuidutils from oslo_utils import uuidutils
import pytest
from selenium.webdriver.common import action_chains from selenium.webdriver.common import action_chains
from selenium.webdriver.common import by from selenium.webdriver.common import by
from selenium.webdriver.common import keys from selenium.webdriver.common import keys
import testtools import testtools
import xvfbwrapper import xvfbwrapper
from horizon.test import helpers
from horizon.test import webdriver from horizon.test import webdriver
from openstack_dashboard.test.integration_tests import config from openstack_dashboard.test.integration_tests import config
from openstack_dashboard.test.integration_tests.pages import loginpage from openstack_dashboard.test.integration_tests.pages import loginpage
@ -103,7 +103,7 @@ class AssertsMixin(object):
return self.assertEqual(list(actual), [False] * len(actual)) return self.assertEqual(list(actual), [False] * len(actual))
@pytest.mark.integration @helpers.pytest_mark('integration')
@tag('integration') @tag('integration')
class BaseTestCase(testtools.TestCase): class BaseTestCase(testtools.TestCase):
@ -307,7 +307,7 @@ class BaseTestCase(testtools.TestCase):
return html_elem.get_attribute("innerHTML").encode("utf-8") return html_elem.get_attribute("innerHTML").encode("utf-8")
@pytest.mark.integration @helpers.pytest_mark('integration')
@tag('integration') @tag('integration')
class TestCase(BaseTestCase, AssertsMixin): class TestCase(BaseTestCase, AssertsMixin):