Skip unit tests which require optional dependencies (#9031)

If we are lacking an optional dependency, skip the tests that rely on it.
This commit is contained in:
Richard van der Hoff 2021-01-07 11:41:28 +00:00 committed by GitHub
parent eee3c3c52f
commit 8d3d264052
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 91 additions and 14 deletions

1
changelog.d/9031.misc Normal file
View File

@ -0,0 +1 @@
Fix running unit tests when optional dependencies are not installed.

View File

@ -24,7 +24,6 @@ import pymacaroons
from twisted.web.resource import Resource from twisted.web.resource import Resource
from synapse.api.errors import RedirectException from synapse.api.errors import RedirectException
from synapse.handlers.oidc_handler import OidcError
from synapse.handlers.sso import MappingException from synapse.handlers.sso import MappingException
from synapse.rest.client.v1 import login from synapse.rest.client.v1 import login
from synapse.rest.synapse.client.pick_username import pick_username_resource from synapse.rest.synapse.client.pick_username import pick_username_resource
@ -34,6 +33,14 @@ from synapse.types import UserID
from tests.test_utils import FakeResponse, simple_async_mock from tests.test_utils import FakeResponse, simple_async_mock
from tests.unittest import HomeserverTestCase, override_config from tests.unittest import HomeserverTestCase, override_config
try:
import authlib # noqa: F401
HAS_OIDC = True
except ImportError:
HAS_OIDC = False
# These are a few constants that are used as config parameters in the tests. # These are a few constants that are used as config parameters in the tests.
ISSUER = "https://issuer/" ISSUER = "https://issuer/"
CLIENT_ID = "test-client-id" CLIENT_ID = "test-client-id"
@ -113,6 +120,9 @@ async def get_json(url):
class OidcHandlerTestCase(HomeserverTestCase): class OidcHandlerTestCase(HomeserverTestCase):
if not HAS_OIDC:
skip = "requires OIDC"
def default_config(self): def default_config(self):
config = super().default_config() config = super().default_config()
config["public_baseurl"] = BASE_URL config["public_baseurl"] = BASE_URL
@ -458,6 +468,8 @@ class OidcHandlerTestCase(HomeserverTestCase):
self.assertRenderedError("fetch_error") self.assertRenderedError("fetch_error")
# Handle code exchange failure # Handle code exchange failure
from synapse.handlers.oidc_handler import OidcError
self.handler._exchange_code = simple_async_mock( self.handler._exchange_code = simple_async_mock(
raises=OidcError("invalid_request") raises=OidcError("invalid_request")
) )
@ -538,6 +550,8 @@ class OidcHandlerTestCase(HomeserverTestCase):
body=b'{"error": "foo", "error_description": "bar"}', body=b'{"error": "foo", "error_description": "bar"}',
) )
) )
from synapse.handlers.oidc_handler import OidcError
exc = self.get_failure(self.handler._exchange_code(code), OidcError) exc = self.get_failure(self.handler._exchange_code(code), OidcError)
self.assertEqual(exc.value.error, "foo") self.assertEqual(exc.value.error, "foo")
self.assertEqual(exc.value.error_description, "bar") self.assertEqual(exc.value.error_description, "bar")
@ -829,6 +843,9 @@ class OidcHandlerTestCase(HomeserverTestCase):
class UsernamePickerTestCase(HomeserverTestCase): class UsernamePickerTestCase(HomeserverTestCase):
if not HAS_OIDC:
skip = "requires OIDC"
servlets = [login.register_servlets] servlets = [login.register_servlets]
def default_config(self): def default_config(self):

View File

@ -4,7 +4,10 @@ import urllib.parse
from mock import Mock from mock import Mock
try:
import jwt import jwt
except ImportError:
jwt = None
import synapse.rest.admin import synapse.rest.admin
from synapse.appservice import ApplicationService from synapse.appservice import ApplicationService
@ -460,6 +463,9 @@ class CASTestCase(unittest.HomeserverTestCase):
class JWTTestCase(unittest.HomeserverTestCase): class JWTTestCase(unittest.HomeserverTestCase):
if not jwt:
skip = "requires jwt"
servlets = [ servlets = [
synapse.rest.admin.register_servlets_for_client_rest_resource, synapse.rest.admin.register_servlets_for_client_rest_resource,
login.register_servlets, login.register_servlets,
@ -628,6 +634,9 @@ class JWTTestCase(unittest.HomeserverTestCase):
# RSS256, with a public key configured in synapse as "jwt_secret", and tokens # RSS256, with a public key configured in synapse as "jwt_secret", and tokens
# signed by the private key. # signed by the private key.
class JWTPubKeyTestCase(unittest.HomeserverTestCase): class JWTPubKeyTestCase(unittest.HomeserverTestCase):
if not jwt:
skip = "requires jwt"
servlets = [ servlets = [
login.register_servlets, login.register_servlets,
] ]

View File

@ -26,8 +26,10 @@ from synapse.rest.oidc import OIDCResource
from synapse.types import JsonDict, UserID from synapse.types import JsonDict, UserID
from tests import unittest from tests import unittest
from tests.handlers.test_oidc import HAS_OIDC
from tests.rest.client.v1.utils import TEST_OIDC_CONFIG from tests.rest.client.v1.utils import TEST_OIDC_CONFIG
from tests.server import FakeChannel from tests.server import FakeChannel
from tests.unittest import override_config, skip_unless
class DummyRecaptchaChecker(UserInteractiveAuthChecker): class DummyRecaptchaChecker(UserInteractiveAuthChecker):
@ -158,18 +160,20 @@ class UIAuthTests(unittest.HomeserverTestCase):
def default_config(self): def default_config(self):
config = super().default_config() config = super().default_config()
config["public_baseurl"] = "https://synapse.test"
if HAS_OIDC:
# we enable OIDC as a way of testing SSO flows # we enable OIDC as a way of testing SSO flows
oidc_config = {} oidc_config = {}
oidc_config.update(TEST_OIDC_CONFIG) oidc_config.update(TEST_OIDC_CONFIG)
oidc_config["allow_existing_users"] = True oidc_config["allow_existing_users"] = True
config["oidc_config"] = oidc_config config["oidc_config"] = oidc_config
config["public_baseurl"] = "https://synapse.test"
return config return config
def create_resource_dict(self): def create_resource_dict(self):
resource_dict = super().create_resource_dict() resource_dict = super().create_resource_dict()
if HAS_OIDC:
# mount the OIDC resource at /_synapse/oidc # mount the OIDC resource at /_synapse/oidc
resource_dict["/_synapse/oidc"] = OIDCResource(self.hs) resource_dict["/_synapse/oidc"] = OIDCResource(self.hs)
return resource_dict return resource_dict
@ -380,6 +384,8 @@ class UIAuthTests(unittest.HomeserverTestCase):
# Note that *no auth* information is provided, not even a session iD! # Note that *no auth* information is provided, not even a session iD!
self.delete_device(self.user_tok, self.device_id, 200) self.delete_device(self.user_tok, self.device_id, 200)
@skip_unless(HAS_OIDC, "requires OIDC")
@override_config({"oidc_config": TEST_OIDC_CONFIG})
def test_does_not_offer_password_for_sso_user(self): def test_does_not_offer_password_for_sso_user(self):
login_resp = self.helper.login_via_oidc("username") login_resp = self.helper.login_via_oidc("username")
user_tok = login_resp["access_token"] user_tok = login_resp["access_token"]
@ -393,13 +399,13 @@ class UIAuthTests(unittest.HomeserverTestCase):
self.assertEqual(flows, [{"stages": ["m.login.sso"]}]) self.assertEqual(flows, [{"stages": ["m.login.sso"]}])
def test_does_not_offer_sso_for_password_user(self): def test_does_not_offer_sso_for_password_user(self):
# now call the device deletion API: we should get the option to auth with SSO
# and not password.
channel = self.delete_device(self.user_tok, self.device_id, 401) channel = self.delete_device(self.user_tok, self.device_id, 401)
flows = channel.json_body["flows"] flows = channel.json_body["flows"]
self.assertEqual(flows, [{"stages": ["m.login.password"]}]) self.assertEqual(flows, [{"stages": ["m.login.password"]}])
@skip_unless(HAS_OIDC, "requires OIDC")
@override_config({"oidc_config": TEST_OIDC_CONFIG})
def test_offers_both_flows_for_upgraded_user(self): def test_offers_both_flows_for_upgraded_user(self):
"""A user that had a password and then logged in with SSO should get both flows """A user that had a password and then logged in with SSO should get both flows
""" """

View File

@ -26,8 +26,15 @@ from twisted.test.proto_helpers import AccumulatingProtocol
from tests import unittest from tests import unittest
from tests.server import FakeTransport from tests.server import FakeTransport
try:
import lxml
except ImportError:
lxml = None
class URLPreviewTests(unittest.HomeserverTestCase): class URLPreviewTests(unittest.HomeserverTestCase):
if not lxml:
skip = "url preview feature requires lxml"
hijack_auth = True hijack_auth = True
user_id = "@test:user" user_id = "@test:user"

View File

@ -20,8 +20,16 @@ from synapse.rest.media.v1.preview_url_resource import (
from . import unittest from . import unittest
try:
import lxml
except ImportError:
lxml = None
class PreviewTestCase(unittest.TestCase): class PreviewTestCase(unittest.TestCase):
if not lxml:
skip = "url preview feature requires lxml"
def test_long_summarize(self): def test_long_summarize(self):
example_paras = [ example_paras = [
"""Tromsø (Norwegian pronunciation: [ˈtrʊmsœ] ( listen); Northern Sami: """Tromsø (Norwegian pronunciation: [ˈtrʊmsœ] ( listen); Northern Sami:
@ -137,6 +145,9 @@ class PreviewTestCase(unittest.TestCase):
class PreviewUrlTestCase(unittest.TestCase): class PreviewUrlTestCase(unittest.TestCase):
if not lxml:
skip = "url preview feature requires lxml"
def test_simple(self): def test_simple(self):
html = """ html = """
<html> <html>

View File

@ -20,7 +20,7 @@ import hmac
import inspect import inspect
import logging import logging
import time import time
from typing import Dict, Iterable, Optional, Tuple, Type, TypeVar, Union from typing import Callable, Dict, Iterable, Optional, Tuple, Type, TypeVar, Union
from mock import Mock, patch from mock import Mock, patch
@ -736,3 +736,29 @@ def override_config(extra_config):
return func return func
return decorator return decorator
TV = TypeVar("TV")
def skip_unless(condition: bool, reason: str) -> Callable[[TV], TV]:
"""A test decorator which will skip the decorated test unless a condition is set
For example:
class MyTestCase(TestCase):
@skip_unless(HAS_FOO, "Cannot test without foo")
def test_foo(self):
...
Args:
condition: If true, the test will be skipped
reason: the reason to give for skipping the test
"""
def decorator(f: TV) -> TV:
if not condition:
f.skip = reason # type: ignore
return f
return decorator