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

Skip unit tests which require optional dependencies #9031

Merged
merged 1 commit into from
Jan 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Comment on lines -396 to -397
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was just a lost comment I noticed while I was in here.

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