Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Skip unit tests which require optional dependencies
Browse files Browse the repository at this point in the history
If we are lacking an optional dependency, skip the tests that rely on it.
  • Loading branch information
richvdh committed Jan 7, 2021
1 parent 8f08021 commit 2ae3876
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 13 deletions.
1 change: 1 addition & 0 deletions changelog.d/9031.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix running unit tests when optional dependencies are not installed.
19 changes: 18 additions & 1 deletion tests/handlers/test_oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
from twisted.web.resource import Resource

from synapse.api.errors import RedirectException
from synapse.handlers.oidc_handler import OidcError
from synapse.handlers.sso import MappingException
from synapse.rest.client.v1 import login
from synapse.rest.synapse.client.pick_username import pick_username_resource
Expand All @@ -34,6 +33,14 @@
from tests.test_utils import FakeResponse, simple_async_mock
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.
ISSUER = "https://issuer/"
CLIENT_ID = "test-client-id"
Expand Down Expand Up @@ -113,6 +120,9 @@ async def get_json(url):


class OidcHandlerTestCase(HomeserverTestCase):
if not HAS_OIDC:
skip = "requires OIDC"

def default_config(self):
config = super().default_config()
config["public_baseurl"] = BASE_URL
Expand Down Expand Up @@ -458,6 +468,8 @@ def test_callback(self):
self.assertRenderedError("fetch_error")

# Handle code exchange failure
from synapse.handlers.oidc_handler import OidcError

self.handler._exchange_code = simple_async_mock(
raises=OidcError("invalid_request")
)
Expand Down Expand Up @@ -538,6 +550,8 @@ def test_exchange_code(self):
body=b'{"error": "foo", "error_description": "bar"}',
)
)
from synapse.handlers.oidc_handler import OidcError

exc = self.get_failure(self.handler._exchange_code(code), OidcError)
self.assertEqual(exc.value.error, "foo")
self.assertEqual(exc.value.error_description, "bar")
Expand Down Expand Up @@ -829,6 +843,9 @@ def test_null_localpart(self):


class UsernamePickerTestCase(HomeserverTestCase):
if not HAS_OIDC:
skip = "requires OIDC"

servlets = [login.register_servlets]

def default_config(self):
Expand Down
11 changes: 10 additions & 1 deletion tests/rest/client/v1/test_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

from mock import Mock

import jwt
try:
import jwt
except ImportError:
jwt = None

import synapse.rest.admin
from synapse.appservice import ApplicationService
Expand Down Expand Up @@ -460,6 +463,9 @@ def test_deactivated_user(self):


class JWTTestCase(unittest.HomeserverTestCase):
if not jwt:
skip = "requires jwt"

servlets = [
synapse.rest.admin.register_servlets_for_client_rest_resource,
login.register_servlets,
Expand Down Expand Up @@ -628,6 +634,9 @@ def test_login_no_token(self):
# RSS256, with a public key configured in synapse as "jwt_secret", and tokens
# signed by the private key.
class JWTPubKeyTestCase(unittest.HomeserverTestCase):
if not jwt:
skip = "requires jwt"

servlets = [
login.register_servlets,
]
Expand Down
26 changes: 16 additions & 10 deletions tests/rest/client/v2_alpha/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
from synapse.types import JsonDict, UserID

from tests import unittest
from tests.handlers.test_oidc import HAS_OIDC
from tests.rest.client.v1.utils import TEST_OIDC_CONFIG
from tests.server import FakeChannel
from tests.unittest import override_config, skip_unless


class DummyRecaptchaChecker(UserInteractiveAuthChecker):
Expand Down Expand Up @@ -158,20 +160,22 @@ class UIAuthTests(unittest.HomeserverTestCase):

def default_config(self):
config = super().default_config()
config["public_baseurl"] = "https://synapse.test"

# we enable OIDC as a way of testing SSO flows
oidc_config = {}
oidc_config.update(TEST_OIDC_CONFIG)
oidc_config["allow_existing_users"] = True
if HAS_OIDC:
# we enable OIDC as a way of testing SSO flows
oidc_config = {}
oidc_config.update(TEST_OIDC_CONFIG)
oidc_config["allow_existing_users"] = True
config["oidc_config"] = oidc_config

config["oidc_config"] = oidc_config
config["public_baseurl"] = "https://synapse.test"
return config

def create_resource_dict(self):
resource_dict = super().create_resource_dict()
# mount the OIDC resource at /_synapse/oidc
resource_dict["/_synapse/oidc"] = OIDCResource(self.hs)
if HAS_OIDC:
# mount the OIDC resource at /_synapse/oidc
resource_dict["/_synapse/oidc"] = OIDCResource(self.hs)
return resource_dict

def prepare(self, reactor, clock, hs):
Expand Down Expand Up @@ -380,6 +384,8 @@ def test_can_reuse_session(self):
# Note that *no auth* information is provided, not even a session iD!
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):
login_resp = self.helper.login_via_oidc("username")
user_tok = login_resp["access_token"]
Expand All @@ -393,13 +399,13 @@ def test_does_not_offer_password_for_sso_user(self):
self.assertEqual(flows, [{"stages": ["m.login.sso"]}])

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)

flows = channel.json_body["flows"]
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):
"""A user that had a password and then logged in with SSO should get both flows
"""
Expand Down
7 changes: 7 additions & 0 deletions tests/rest/media/v1/test_url_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,15 @@
from tests import unittest
from tests.server import FakeTransport

try:
import lxml
except ImportError:
lxml = None


class URLPreviewTests(unittest.HomeserverTestCase):
if not lxml:
skip = "url preview feature requires lxml"

hijack_auth = True
user_id = "@test:user"
Expand Down
11 changes: 11 additions & 0 deletions tests/test_preview.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,16 @@

from . import unittest

try:
import lxml
except ImportError:
lxml = None


class PreviewTestCase(unittest.TestCase):
if not lxml:
skip = "url preview feature requires lxml"

def test_long_summarize(self):
example_paras = [
"""Tromsø (Norwegian pronunciation: [ˈtrʊmsœ] ( listen); Northern Sami:
Expand Down Expand Up @@ -137,6 +145,9 @@ def test_small_then_large_summarize(self):


class PreviewUrlTestCase(unittest.TestCase):
if not lxml:
skip = "url preview feature requires lxml"

def test_simple(self):
html = """
<html>
Expand Down
28 changes: 27 additions & 1 deletion tests/unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import inspect
import logging
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

Expand Down Expand Up @@ -736,3 +736,29 @@ def decorator(func):
return func

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

0 comments on commit 2ae3876

Please sign in to comment.