diff options
Diffstat (limited to 'tests/rest')
-rw-r--r-- | tests/rest/admin/test_jwks.py | 8 | ||||
-rw-r--r-- | tests/rest/admin/test_server_notice.py | 136 | ||||
-rw-r--r-- | tests/rest/client/test_auth_issuer.py | 59 | ||||
-rw-r--r-- | tests/rest/client/test_keys.py | 8 | ||||
-rw-r--r-- | tests/rest/client/test_profile.py | 160 | ||||
-rw-r--r-- | tests/rest/client/test_upgrade_room.py | 28 | ||||
-rw-r--r-- | tests/rest/media/test_media_retention.py | 300 | ||||
-rw-r--r-- | tests/rest/test_well_known.py | 8 |
8 files changed, 386 insertions, 321 deletions
diff --git a/tests/rest/admin/test_jwks.py b/tests/rest/admin/test_jwks.py index 6c2b355aa8..3636ea3415 100644 --- a/tests/rest/admin/test_jwks.py +++ b/tests/rest/admin/test_jwks.py @@ -25,13 +25,7 @@ from twisted.web.resource import Resource from synapse.rest.synapse.client import build_synapse_client_resource_tree from tests.unittest import HomeserverTestCase, override_config, skip_unless - -try: - import authlib # noqa: F401 - - HAS_AUTHLIB = True -except ImportError: - HAS_AUTHLIB = False +from tests.utils import HAS_AUTHLIB @skip_unless(HAS_AUTHLIB, "requires authlib") diff --git a/tests/rest/admin/test_server_notice.py b/tests/rest/admin/test_server_notice.py index ceba09ec46..ce5e3a5c1f 100644 --- a/tests/rest/admin/test_server_notice.py +++ b/tests/rest/admin/test_server_notice.py @@ -483,6 +483,33 @@ class ServerNoticeTestCase(unittest.HomeserverTestCase): # second room has new ID self.assertNotEqual(first_room_id, second_room_id) + @override_config( + {"server_notices": {"system_mxid_localpart": "notices", "auto_join": True}} + ) + def test_auto_join(self) -> None: + """ + Tests that the user get automatically joined to the notice room + when `auto_join` setting is used. + """ + # user has no room memberships + self._check_invite_and_join_status(self.other_user, 0, 0) + + # send server notice + server_notice_request_content = { + "user_id": self.other_user, + "content": {"msgtype": "m.text", "body": "test msg one"}, + } + + self.make_request( + "POST", + self.url, + access_token=self.admin_user_tok, + content=server_notice_request_content, + ) + + # user has joined the room + self._check_invite_and_join_status(self.other_user, 0, 1) + @override_config({"server_notices": {"system_mxid_localpart": "notices"}}) def test_update_notice_user_name_when_changed(self) -> None: """ @@ -575,6 +602,115 @@ class ServerNoticeTestCase(unittest.HomeserverTestCase): ) self.assertEqual(notice_user_state["avatar_url"], new_avatar_url) + @override_config( + { + "server_notices": { + "system_mxid_localpart": "notices", + "room_avatar_url": "test/url", + "room_topic": "Test Topic", + } + } + ) + def test_notice_room_avatar_and_topic(self) -> None: + """ + Tests that using `room_avatar_url` and `room_topic` config properly sets + those properties for the created notice rooms. + """ + server_notice_request_content = { + "user_id": self.other_user, + "content": {"msgtype": "m.text", "body": "test msg one"}, + } + + self.make_request( + "POST", + self.url, + access_token=self.admin_user_tok, + content=server_notice_request_content, + ) + + invited_rooms = self._check_invite_and_join_status(self.other_user, 1, 0) + notice_room_id = invited_rooms[0].room_id + self.helper.join( + room=notice_room_id, user=self.other_user, tok=self.other_user_token + ) + + room_avatar_state = self.helper.get_state( + notice_room_id, + "m.room.avatar", + self.other_user_token, + state_key="", + ) + self.assertEqual(room_avatar_state["url"], "test/url") + + room_topic_state = self.helper.get_state( + notice_room_id, + "m.room.topic", + self.other_user_token, + state_key="", + ) + self.assertEqual(room_topic_state["topic"], "Test Topic") + + @override_config( + { + "server_notices": { + "system_mxid_localpart": "notices", + "room_avatar_url": "test/url", + } + } + ) + def test_update_room_avatar_when_changed(self) -> None: + """ + Tests that existing server notices room avatar is updated when it is + different from the one in homeserver config. + """ + server_notice_request_content = { + "user_id": self.other_user, + "content": {"msgtype": "m.text", "body": "test msg one"}, + } + + self.make_request( + "POST", + self.url, + access_token=self.admin_user_tok, + content=server_notice_request_content, + ) + + invited_rooms = self._check_invite_and_join_status(self.other_user, 1, 0) + notice_room_id = invited_rooms[0].room_id + self.helper.join( + room=notice_room_id, user=self.other_user, tok=self.other_user_token + ) + + room_avatar_state = self.helper.get_state( + notice_room_id, + "m.room.avatar", + self.other_user_token, + state_key="", + ) + self.assertEqual(room_avatar_state["url"], "test/url") + + # simulate a change in server config after a server restart. + new_avatar_url = "test/new-url" + self.server_notices_manager._config.servernotices.server_notices_room_avatar_url = ( + new_avatar_url + ) + self.server_notices_manager.get_or_create_notice_room_for_user.cache.invalidate_all() + + self.make_request( + "POST", + self.url, + access_token=self.admin_user_tok, + content=server_notice_request_content, + ) + + room_avatar_state = self.helper.get_state( + notice_room_id, + "m.room.avatar", + self.other_user_token, + state_key="", + ) + self.assertEqual(room_avatar_state["url"], new_avatar_url) + def _check_invite_and_join_status( self, user_id: str, expected_invites: int, expected_memberships: int ) -> Sequence[RoomsForUser]: diff --git a/tests/rest/client/test_auth_issuer.py b/tests/rest/client/test_auth_issuer.py new file mode 100644 index 0000000000..964baeec32 --- /dev/null +++ b/tests/rest/client/test_auth_issuer.py @@ -0,0 +1,59 @@ +# Copyright 2023 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from http import HTTPStatus + +from synapse.rest.client import auth_issuer + +from tests.unittest import HomeserverTestCase, override_config, skip_unless +from tests.utils import HAS_AUTHLIB + +ISSUER = "https://account.example.com/" + + +class AuthIssuerTestCase(HomeserverTestCase): + servlets = [ + auth_issuer.register_servlets, + ] + + def test_returns_404_when_msc3861_disabled(self) -> None: + # Make an unauthenticated request for the discovery info. + channel = self.make_request( + "GET", + "/_matrix/client/unstable/org.matrix.msc2965/auth_issuer", + ) + self.assertEqual(channel.code, HTTPStatus.NOT_FOUND) + + @skip_unless(HAS_AUTHLIB, "requires authlib") + @override_config( + { + "disable_registration": True, + "experimental_features": { + "msc3861": { + "enabled": True, + "issuer": ISSUER, + "client_id": "David Lister", + "client_auth_method": "client_secret_post", + "client_secret": "Who shot Mister Burns?", + } + }, + } + ) + def test_returns_issuer_when_oidc_enabled(self) -> None: + # Make an unauthenticated request for the discovery info. + channel = self.make_request( + "GET", + "/_matrix/client/unstable/org.matrix.msc2965/auth_issuer", + ) + self.assertEqual(channel.code, HTTPStatus.OK) + self.assertEqual(channel.json_body, {"issuer": ISSUER}) diff --git a/tests/rest/client/test_keys.py b/tests/rest/client/test_keys.py index fb0f451a5c..e99160c5ac 100644 --- a/tests/rest/client/test_keys.py +++ b/tests/rest/client/test_keys.py @@ -36,13 +36,7 @@ from synapse.types import JsonDict, Requester, create_requester from tests import unittest from tests.http.server._base import make_request_with_cancellation_test from tests.unittest import override_config - -try: - import authlib # noqa: F401 - - HAS_AUTHLIB = True -except ImportError: - HAS_AUTHLIB = False +from tests.utils import HAS_AUTHLIB class KeyQueryTestCase(unittest.HomeserverTestCase): diff --git a/tests/rest/client/test_profile.py b/tests/rest/client/test_profile.py index 13e36731a5..b9852928c0 100644 --- a/tests/rest/client/test_profile.py +++ b/tests/rest/client/test_profile.py @@ -318,6 +318,166 @@ class ProfileTestCase(unittest.HomeserverTestCase): ) self.assertEqual(channel.code, 200, channel.result) + @unittest.override_config( + {"experimental_features": {"msc4069_profile_inhibit_propagation": True}} + ) + def test_msc4069_inhibit_propagation(self) -> None: + """Tests to ensure profile update propagation can be inhibited.""" + for prop in ["avatar_url", "displayname"]: + room_id = self.helper.create_room_as(tok=self.owner_tok) + + channel = self.make_request( + "PUT", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + content={"membership": "join", prop: "mxc://my.server/existing"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + channel = self.make_request( + "PUT", + f"/profile/{self.owner}/{prop}?org.matrix.msc4069.propagate=false", + content={prop: "http://my.server/pic.gif"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + res = ( + self._get_avatar_url() + if prop == "avatar_url" + else self._get_displayname() + ) + self.assertEqual(res, "http://my.server/pic.gif") + + channel = self.make_request( + "GET", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + self.assertEqual(channel.json_body.get(prop), "mxc://my.server/existing") + + def test_msc4069_inhibit_propagation_disabled(self) -> None: + """Tests to ensure profile update propagation inhibit flags are ignored when the + experimental flag is not enabled. + """ + for prop in ["avatar_url", "displayname"]: + room_id = self.helper.create_room_as(tok=self.owner_tok) + + channel = self.make_request( + "PUT", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + content={"membership": "join", prop: "mxc://my.server/existing"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + channel = self.make_request( + "PUT", + f"/profile/{self.owner}/{prop}?org.matrix.msc4069.propagate=false", + content={prop: "http://my.server/pic.gif"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + res = ( + self._get_avatar_url() + if prop == "avatar_url" + else self._get_displayname() + ) + self.assertEqual(res, "http://my.server/pic.gif") + + channel = self.make_request( + "GET", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + # The ?propagate=false should be ignored by the server because the config flag + # isn't enabled. + self.assertEqual(channel.json_body.get(prop), "http://my.server/pic.gif") + + def test_msc4069_inhibit_propagation_default(self) -> None: + """Tests to ensure profile update propagation happens by default.""" + for prop in ["avatar_url", "displayname"]: + room_id = self.helper.create_room_as(tok=self.owner_tok) + + channel = self.make_request( + "PUT", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + content={"membership": "join", prop: "mxc://my.server/existing"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + channel = self.make_request( + "PUT", + f"/profile/{self.owner}/{prop}", + content={prop: "http://my.server/pic.gif"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + res = ( + self._get_avatar_url() + if prop == "avatar_url" + else self._get_displayname() + ) + self.assertEqual(res, "http://my.server/pic.gif") + + channel = self.make_request( + "GET", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + # The ?propagate=false should be ignored by the server because the config flag + # isn't enabled. + self.assertEqual(channel.json_body.get(prop), "http://my.server/pic.gif") + + @unittest.override_config( + {"experimental_features": {"msc4069_profile_inhibit_propagation": True}} + ) + def test_msc4069_inhibit_propagation_like_default(self) -> None: + """Tests to ensure clients can request explicit profile propagation.""" + for prop in ["avatar_url", "displayname"]: + room_id = self.helper.create_room_as(tok=self.owner_tok) + + channel = self.make_request( + "PUT", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + content={"membership": "join", prop: "mxc://my.server/existing"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + channel = self.make_request( + "PUT", + f"/profile/{self.owner}/{prop}?org.matrix.msc4069.propagate=true", + content={prop: "http://my.server/pic.gif"}, + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + res = ( + self._get_avatar_url() + if prop == "avatar_url" + else self._get_displayname() + ) + self.assertEqual(res, "http://my.server/pic.gif") + + channel = self.make_request( + "GET", + f"/rooms/{room_id}/state/m.room.member/{self.owner}", + access_token=self.owner_tok, + ) + self.assertEqual(channel.code, 200, channel.result) + + # The client requested ?propagate=true, so it should have happened. + self.assertEqual(channel.json_body.get(prop), "http://my.server/pic.gif") + def _setup_local_files(self, names_and_props: Dict[str, Dict[str, Any]]) -> None: """Stores metadata about files in the database. diff --git a/tests/rest/client/test_upgrade_room.py b/tests/rest/client/test_upgrade_room.py index a497f41fb2..7038e42058 100644 --- a/tests/rest/client/test_upgrade_room.py +++ b/tests/rest/client/test_upgrade_room.py @@ -252,6 +252,34 @@ class UpgradeRoomTest(unittest.HomeserverTestCase): # We should now have an integer power level. self.assertEqual(new_power_levels["users"][self.creator], 100, new_power_levels) + def test_events_field_missing(self) -> None: + """Regression test for https://github.com/matrix-org/synapse/issues/16715.""" + # Create a new room. + room_id = self.helper.create_room_as( + self.creator, tok=self.creator_token, room_version="10" + ) + self.helper.join(room_id, self.other, tok=self.other_token) + + # Retrieve the room's current power levels. + power_levels = self.helper.get_state( + room_id, + "m.room.power_levels", + tok=self.creator_token, + ) + + # Remove the events field and re-set the power levels. + del power_levels["events"] + self.helper.send_state( + room_id, + "m.room.power_levels", + body=power_levels, + tok=self.creator_token, + ) + + # Upgrade the room. Check the homeserver reports success. + channel = self._upgrade_room(room_id=room_id) + self.assertEqual(200, channel.code, channel.result) + def test_space(self) -> None: """Test upgrading a space.""" diff --git a/tests/rest/media/test_media_retention.py b/tests/rest/media/test_media_retention.py deleted file mode 100644 index 7f613f351b..0000000000 --- a/tests/rest/media/test_media_retention.py +++ /dev/null @@ -1,300 +0,0 @@ -# -# This file is licensed under the Affero General Public License (AGPL) version 3. -# -# Copyright (C) 2023 New Vector, Ltd -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# See the GNU Affero General Public License for more details: -# <https://www.gnu.org/licenses/agpl-3.0.html>. -# -# Originally licensed under the Apache License, Version 2.0: -# <http://www.apache.org/licenses/LICENSE-2.0>. -# -# [This file includes modifications made by New Vector Limited] -# -# - -import io -from typing import Iterable, Optional - -from matrix_common.types.mxc_uri import MXCUri - -from twisted.test.proto_helpers import MemoryReactor - -from synapse.rest import admin -from synapse.rest.client import login, register, room -from synapse.server import HomeServer -from synapse.types import UserID -from synapse.util import Clock - -from tests import unittest -from tests.unittest import override_config -from tests.utils import MockClock - - -class MediaRetentionTestCase(unittest.HomeserverTestCase): - ONE_DAY_IN_MS = 24 * 60 * 60 * 1000 - THIRTY_DAYS_IN_MS = 30 * ONE_DAY_IN_MS - - servlets = [ - room.register_servlets, - login.register_servlets, - register.register_servlets, - admin.register_servlets_for_client_rest_resource, - ] - - def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer: - # We need to be able to test advancing time in the homeserver, so we - # replace the test homeserver's default clock with a MockClock, which - # supports advancing time. - return self.setup_test_homeserver(clock=MockClock()) - - def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: - self.remote_server_name = "remote.homeserver" - self.store = hs.get_datastores().main - - # Create a user to upload media with - test_user_id = self.register_user("alice", "password") - - # Inject media (recently accessed, old access, never accessed, old access - # quarantined media) into both the local store and the remote cache, plus - # one additional local media that is marked as protected from quarantine. - media_repository = hs.get_media_repository() - test_media_content = b"example string" - - def _create_media_and_set_attributes( - last_accessed_ms: Optional[int], - is_quarantined: Optional[bool] = False, - is_protected: Optional[bool] = False, - ) -> MXCUri: - # "Upload" some media to the local media store - mxc_uri: MXCUri = self.get_success( - media_repository.create_content( - media_type="text/plain", - upload_name=None, - content=io.BytesIO(test_media_content), - content_length=len(test_media_content), - auth_user=UserID.from_string(test_user_id), - ) - ) - - # Set the last recently accessed time for this media - if last_accessed_ms is not None: - self.get_success( - self.store.update_cached_last_access_time( - local_media=(mxc_uri.media_id,), - remote_media=(), - time_ms=last_accessed_ms, - ) - ) - - if is_quarantined: - # Mark this media as quarantined - self.get_success( - self.store.quarantine_media_by_id( - server_name=self.hs.config.server.server_name, - media_id=mxc_uri.media_id, - quarantined_by="@theadmin:test", - ) - ) - - if is_protected: - # Mark this media as protected from quarantine - self.get_success( - self.store.mark_local_media_as_safe( - media_id=mxc_uri.media_id, - safe=True, - ) - ) - - return mxc_uri - - def _cache_remote_media_and_set_attributes( - media_id: str, - last_accessed_ms: Optional[int], - is_quarantined: Optional[bool] = False, - ) -> MXCUri: - # Pretend to cache some remote media - self.get_success( - self.store.store_cached_remote_media( - origin=self.remote_server_name, - media_id=media_id, - media_type="text/plain", - media_length=1, - time_now_ms=clock.time_msec(), - upload_name="testfile.txt", - filesystem_id="abcdefg12345", - ) - ) - - # Set the last recently accessed time for this media - if last_accessed_ms is not None: - self.get_success( - hs.get_datastores().main.update_cached_last_access_time( - local_media=(), - remote_media=((self.remote_server_name, media_id),), - time_ms=last_accessed_ms, - ) - ) - - if is_quarantined: - # Mark this media as quarantined - self.get_success( - self.store.quarantine_media_by_id( - server_name=self.remote_server_name, - media_id=media_id, - quarantined_by="@theadmin:test", - ) - ) - - return MXCUri(self.remote_server_name, media_id) - - # Start with the local media store - self.local_recently_accessed_media = _create_media_and_set_attributes( - last_accessed_ms=self.THIRTY_DAYS_IN_MS, - ) - self.local_not_recently_accessed_media = _create_media_and_set_attributes( - last_accessed_ms=self.ONE_DAY_IN_MS, - ) - self.local_not_recently_accessed_quarantined_media = ( - _create_media_and_set_attributes( - last_accessed_ms=self.ONE_DAY_IN_MS, - is_quarantined=True, - ) - ) - self.local_not_recently_accessed_protected_media = ( - _create_media_and_set_attributes( - last_accessed_ms=self.ONE_DAY_IN_MS, - is_protected=True, - ) - ) - self.local_never_accessed_media = _create_media_and_set_attributes( - last_accessed_ms=None, - ) - - # And now the remote media store - self.remote_recently_accessed_media = _cache_remote_media_and_set_attributes( - media_id="a", - last_accessed_ms=self.THIRTY_DAYS_IN_MS, - ) - self.remote_not_recently_accessed_media = ( - _cache_remote_media_and_set_attributes( - media_id="b", - last_accessed_ms=self.ONE_DAY_IN_MS, - ) - ) - self.remote_not_recently_accessed_quarantined_media = ( - _cache_remote_media_and_set_attributes( - media_id="c", - last_accessed_ms=self.ONE_DAY_IN_MS, - is_quarantined=True, - ) - ) - # Remote media will always have a "last accessed" attribute, as it would not - # be fetched from the remote homeserver unless instigated by a user. - - @override_config( - { - "media_retention": { - # Enable retention for local media - "local_media_lifetime": "30d" - # Cached remote media should not be purged - } - } - ) - def test_local_media_retention(self) -> None: - """ - Tests that local media that have not been accessed recently is purged, while - cached remote media is unaffected. - """ - # Advance 31 days (in seconds) - self.reactor.advance(31 * 24 * 60 * 60) - - # Check that media has been correctly purged. - # Local media accessed <30 days ago should still exist. - # Remote media should be unaffected. - self._assert_if_mxc_uris_purged( - purged=[ - self.local_not_recently_accessed_media, - self.local_never_accessed_media, - ], - not_purged=[ - self.local_recently_accessed_media, - self.local_not_recently_accessed_quarantined_media, - self.local_not_recently_accessed_protected_media, - self.remote_recently_accessed_media, - self.remote_not_recently_accessed_media, - self.remote_not_recently_accessed_quarantined_media, - ], - ) - - @override_config( - { - "media_retention": { - # Enable retention for cached remote media - "remote_media_lifetime": "30d" - # Local media should not be purged - } - } - ) - def test_remote_media_cache_retention(self) -> None: - """ - Tests that entries from the remote media cache that have not been accessed - recently is purged, while local media is unaffected. - """ - # Advance 31 days (in seconds) - self.reactor.advance(31 * 24 * 60 * 60) - - # Check that media has been correctly purged. - # Local media should be unaffected. - # Remote media accessed <30 days ago should still exist. - self._assert_if_mxc_uris_purged( - purged=[ - self.remote_not_recently_accessed_media, - ], - not_purged=[ - self.remote_recently_accessed_media, - self.local_recently_accessed_media, - self.local_not_recently_accessed_media, - self.local_not_recently_accessed_quarantined_media, - self.local_not_recently_accessed_protected_media, - self.remote_not_recently_accessed_quarantined_media, - self.local_never_accessed_media, - ], - ) - - def _assert_if_mxc_uris_purged( - self, purged: Iterable[MXCUri], not_purged: Iterable[MXCUri] - ) -> None: - def _assert_mxc_uri_purge_state(mxc_uri: MXCUri, expect_purged: bool) -> None: - """Given an MXC URI, assert whether it has been purged or not.""" - if mxc_uri.server_name == self.hs.config.server.server_name: - found_media = bool( - self.get_success(self.store.get_local_media(mxc_uri.media_id)) - ) - else: - found_media = bool( - self.get_success( - self.store.get_cached_remote_media( - mxc_uri.server_name, mxc_uri.media_id - ) - ) - ) - - if expect_purged: - self.assertFalse(found_media, msg=f"{mxc_uri} unexpectedly not purged") - else: - self.assertTrue( - found_media, - msg=f"{mxc_uri} unexpectedly purged", - ) - - # Assert that the given MXC URIs have either been correctly purged or not. - for mxc_uri in purged: - _assert_mxc_uri_purge_state(mxc_uri, expect_purged=True) - for mxc_uri in not_purged: - _assert_mxc_uri_purge_state(mxc_uri, expect_purged=False) diff --git a/tests/rest/test_well_known.py b/tests/rest/test_well_known.py index 682aa63e5b..e166c13bc1 100644 --- a/tests/rest/test_well_known.py +++ b/tests/rest/test_well_known.py @@ -22,13 +22,7 @@ from twisted.web.resource import Resource from synapse.rest.well_known import well_known_resource from tests import unittest - -try: - import authlib # noqa: F401 - - HAS_AUTHLIB = True -except ImportError: - HAS_AUTHLIB = False +from tests.utils import HAS_AUTHLIB class WellKnownTests(unittest.HomeserverTestCase): |