From 7d9de9c58afbbf92f2689e56b248aabaa768f6a5 Mon Sep 17 00:00:00 2001 From: "Kai A. Hiller" Date: Wed, 15 Dec 2021 15:39:33 +0100 Subject: [PATCH 1/7] Remove dependency on non-standard mock Signed-off-by: Kai A. Hiller --- setup.py | 4 +--- tests/storage/test_background_update.py | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 2c6fb9aacb45..bfca16727eb5 100755 --- a/setup.py +++ b/setup.py @@ -119,9 +119,7 @@ def exec_file(path_segments): # Tests assume that all optional dependencies are installed. # # parameterized_class decorator was introduced in parameterized 0.7.0 -# -# We use `mock` library as that backports `AsyncMock` to Python 3.6 -CONDITIONAL_REQUIREMENTS["test"] = ["parameterized>=0.7.0", "mock>=4.0.0"] +CONDITIONAL_REQUIREMENTS["test"] = ["parameterized>=0.7.0"] CONDITIONAL_REQUIREMENTS["dev"] = ( CONDITIONAL_REQUIREMENTS["lint"] diff --git a/tests/storage/test_background_update.py b/tests/storage/test_background_update.py index d77c001506c6..542b70a1ee6d 100644 --- a/tests/storage/test_background_update.py +++ b/tests/storage/test_background_update.py @@ -12,8 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Use backported mock for AsyncMock support on Python 3.6. -from mock import Mock +from unittest.mock import Mock from twisted.internet.defer import Deferred, ensureDeferred From c812db96257c1526c88c11110bec4045bf7cf24b Mon Sep 17 00:00:00 2001 From: "Kai A. Hiller" Date: Wed, 15 Dec 2021 15:41:22 +0100 Subject: [PATCH 2/7] Replace simple_async_mock with AsyncMock Signed-off-by: Kai A. Hiller --- tests/api/test_auth.py | 79 +++++++++++++++------------- tests/appservice/test_scheduler.py | 43 ++++++++------- tests/events/test_presence_router.py | 5 +- tests/handlers/test_cas.py | 11 ++-- tests/handlers/test_oidc.py | 66 +++++++++++------------ tests/handlers/test_saml.py | 13 +++-- tests/module_api/test_api.py | 5 +- tests/test_utils/__init__.py | 10 ---- 8 files changed, 112 insertions(+), 120 deletions(-) diff --git a/tests/api/test_auth.py b/tests/api/test_auth.py index a2dfa1ed0507..3ae054b72af0 100644 --- a/tests/api/test_auth.py +++ b/tests/api/test_auth.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from unittest.mock import Mock +from unittest.mock import AsyncMock, Mock import pymacaroons @@ -30,7 +30,6 @@ from synapse.types import Requester from tests import unittest -from tests.test_utils import simple_async_mock from tests.unittest import override_config from tests.utils import mock_getRawHeaders @@ -53,15 +52,15 @@ def prepare(self, reactor, clock, hs): # this is overridden for the appservice tests self.store.get_app_service_by_token = Mock(return_value=None) - self.store.insert_client_ip = simple_async_mock(None) - self.store.is_support_user = simple_async_mock(False) + self.store.insert_client_ip = AsyncMock(return_value=None) + self.store.is_support_user = AsyncMock(return_value=False) def test_get_user_by_req_user_valid_token(self): user_info = TokenLookupResult( user_id=self.test_user, token_id=5, device_id="device" ) - self.store.get_user_by_access_token = simple_async_mock(user_info) - self.store.mark_access_token_as_used = simple_async_mock(None) + self.store.get_user_by_access_token = AsyncMock(return_value=user_info) + self.store.mark_access_token_as_used = AsyncMock(return_value=None) request = Mock(args={}) request.args[b"access_token"] = [self.test_token] @@ -70,7 +69,7 @@ def test_get_user_by_req_user_valid_token(self): self.assertEquals(requester.user.to_string(), self.test_user) def test_get_user_by_req_user_bad_token(self): - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_access_token = AsyncMock(return_value=None) request = Mock(args={}) request.args[b"access_token"] = [self.test_token] @@ -83,7 +82,7 @@ def test_get_user_by_req_user_bad_token(self): def test_get_user_by_req_user_missing_token(self): user_info = TokenLookupResult(user_id=self.test_user, token_id=5) - self.store.get_user_by_access_token = simple_async_mock(user_info) + self.store.get_user_by_access_token = AsyncMock(return_value=user_info) request = Mock(args={}) request.requestHeaders.getRawHeaders = mock_getRawHeaders() @@ -98,7 +97,7 @@ def test_get_user_by_req_appservice_valid_token(self): token="foobar", url="a_url", sender=self.test_user, ip_range_whitelist=None ) self.store.get_app_service_by_token = Mock(return_value=app_service) - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_access_token = AsyncMock(return_value=None) request = Mock(args={}) request.getClientIP.return_value = "127.0.0.1" @@ -117,7 +116,7 @@ def test_get_user_by_req_appservice_valid_token_good_ip(self): ip_range_whitelist=IPSet(["192.168/16"]), ) self.store.get_app_service_by_token = Mock(return_value=app_service) - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_access_token = AsyncMock(return_value=None) request = Mock(args={}) request.getClientIP.return_value = "192.168.10.10" @@ -136,7 +135,7 @@ def test_get_user_by_req_appservice_valid_token_bad_ip(self): ip_range_whitelist=IPSet(["192.168/16"]), ) self.store.get_app_service_by_token = Mock(return_value=app_service) - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_access_token = AsyncMock(return_value=None) request = Mock(args={}) request.getClientIP.return_value = "131.111.8.42" @@ -150,7 +149,7 @@ def test_get_user_by_req_appservice_valid_token_bad_ip(self): def test_get_user_by_req_appservice_bad_token(self): self.store.get_app_service_by_token = Mock(return_value=None) - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_access_token = AsyncMock(return_value=None) request = Mock(args={}) request.args[b"access_token"] = [self.test_token] @@ -164,7 +163,7 @@ def test_get_user_by_req_appservice_bad_token(self): def test_get_user_by_req_appservice_missing_token(self): app_service = Mock(token="foobar", url="a_url", sender=self.test_user) self.store.get_app_service_by_token = Mock(return_value=app_service) - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_access_token = AsyncMock(return_value=None) request = Mock(args={}) request.requestHeaders.getRawHeaders = mock_getRawHeaders() @@ -182,8 +181,8 @@ def test_get_user_by_req_appservice_valid_token_valid_user_id(self): app_service.is_interested_in_user = Mock(return_value=True) self.store.get_app_service_by_token = Mock(return_value=app_service) # This just needs to return a truth-y value. - self.store.get_user_by_id = simple_async_mock({"is_guest": False}) - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_id = AsyncMock(return_value={"is_guest": False}) + self.store.get_user_by_access_token = AsyncMock(return_value=None) request = Mock(args={}) request.getClientIP.return_value = "127.0.0.1" @@ -202,7 +201,7 @@ def test_get_user_by_req_appservice_valid_token_bad_user_id(self): ) app_service.is_interested_in_user = Mock(return_value=False) self.store.get_app_service_by_token = Mock(return_value=app_service) - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_access_token = AsyncMock(return_value=None) request = Mock(args={}) request.getClientIP.return_value = "127.0.0.1" @@ -226,10 +225,10 @@ def test_get_user_by_req_appservice_valid_token_valid_device_id(self): app_service.is_interested_in_user = Mock(return_value=True) self.store.get_app_service_by_token = Mock(return_value=app_service) # This just needs to return a truth-y value. - self.store.get_user_by_id = simple_async_mock({"is_guest": False}) - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_id = AsyncMock(return_value={"is_guest": False}) + self.store.get_user_by_access_token = AsyncMock(return_value=None) # This also needs to just return a truth-y value - self.store.get_device = simple_async_mock({"hidden": False}) + self.store.get_device = AsyncMock(return_value={"hidden": False}) request = Mock(args={}) request.getClientIP.return_value = "127.0.0.1" @@ -258,10 +257,10 @@ def test_get_user_by_req_appservice_valid_token_invalid_device_id(self): app_service.is_interested_in_user = Mock(return_value=True) self.store.get_app_service_by_token = Mock(return_value=app_service) # This just needs to return a truth-y value. - self.store.get_user_by_id = simple_async_mock({"is_guest": False}) - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_id = AsyncMock(return_value={"is_guest": False}) + self.store.get_user_by_access_token = AsyncMock(return_value=None) # This also needs to just return a falsey value - self.store.get_device = simple_async_mock(None) + self.store.get_device = AsyncMock(return_value=None) request = Mock(args={}) request.getClientIP.return_value = "127.0.0.1" @@ -275,8 +274,10 @@ def test_get_user_by_req_appservice_valid_token_invalid_device_id(self): self.assertEquals(failure.value.errcode, Codes.EXCLUSIVE) def test_get_user_from_macaroon(self): - self.store.get_user_by_access_token = simple_async_mock( - TokenLookupResult(user_id="@baldrick:matrix.org", device_id="device") + self.store.get_user_by_access_token = AsyncMock( + return_value=TokenLookupResult( + user_id="@baldrick:matrix.org", device_id="device" + ) ) user_id = "@baldrick:matrix.org" @@ -298,8 +299,8 @@ def test_get_user_from_macaroon(self): self.assertEqual(user_info.device_id, "device") def test_get_guest_user_from_macaroon(self): - self.store.get_user_by_id = simple_async_mock({"is_guest": True}) - self.store.get_user_by_access_token = simple_async_mock(None) + self.store.get_user_by_id = AsyncMock(return_value={"is_guest": True}) + self.store.get_user_by_access_token = AsyncMock(return_value=None) user_id = "@baldrick:matrix.org" macaroon = pymacaroons.Macaroon( @@ -329,7 +330,7 @@ def test_blocking_mau(self): self.auth_blocking._limit_usage_by_mau = True - self.store.get_monthly_active_count = simple_async_mock(lots_of_users) + self.store.get_monthly_active_count = AsyncMock(return_value=lots_of_users) e = self.get_failure(self.auth.check_auth_blocking(), ResourceLimitError) self.assertEquals(e.value.admin_contact, self.hs.config.server.admin_contact) @@ -337,22 +338,24 @@ def test_blocking_mau(self): self.assertEquals(e.value.code, 403) # Ensure does not throw an error - self.store.get_monthly_active_count = simple_async_mock(small_number_of_users) + self.store.get_monthly_active_count = AsyncMock( + return_value=small_number_of_users + ) self.get_success(self.auth.check_auth_blocking()) def test_blocking_mau__depending_on_user_type(self): self.auth_blocking._max_mau_value = 50 self.auth_blocking._limit_usage_by_mau = True - self.store.get_monthly_active_count = simple_async_mock(100) + self.store.get_monthly_active_count = AsyncMock(return_value=100) # Support users allowed self.get_success(self.auth.check_auth_blocking(user_type=UserTypes.SUPPORT)) - self.store.get_monthly_active_count = simple_async_mock(100) + self.store.get_monthly_active_count = AsyncMock(return_value=100) # Bots not allowed self.get_failure( self.auth.check_auth_blocking(user_type=UserTypes.BOT), ResourceLimitError ) - self.store.get_monthly_active_count = simple_async_mock(100) + self.store.get_monthly_active_count = AsyncMock(return_value=100) # Real users not allowed self.get_failure(self.auth.check_auth_blocking(), ResourceLimitError) @@ -361,9 +364,9 @@ def test_blocking_mau__appservice_requester_allowed_when_not_tracking_ips(self): self.auth_blocking._limit_usage_by_mau = True self.auth_blocking._track_appservice_user_ips = False - self.store.get_monthly_active_count = simple_async_mock(100) - self.store.user_last_seen_monthly_active = simple_async_mock() - self.store.is_trial_user = simple_async_mock() + self.store.get_monthly_active_count = AsyncMock(return_value=100) + self.store.user_last_seen_monthly_active = AsyncMock(return_value=None) + self.store.is_trial_user = AsyncMock(return_value=False) appservice = ApplicationService( "abcd", @@ -390,9 +393,9 @@ def test_blocking_mau__appservice_requester_disallowed_when_tracking_ips(self): self.auth_blocking._limit_usage_by_mau = True self.auth_blocking._track_appservice_user_ips = True - self.store.get_monthly_active_count = simple_async_mock(100) - self.store.user_last_seen_monthly_active = simple_async_mock() - self.store.is_trial_user = simple_async_mock() + self.store.get_monthly_active_count = AsyncMock(return_value=100) + self.store.user_last_seen_monthly_active = AsyncMock(return_value=None) + self.store.is_trial_user = AsyncMock(return_value=False) appservice = ApplicationService( "abcd", @@ -419,7 +422,7 @@ def test_blocking_mau__appservice_requester_disallowed_when_tracking_ips(self): def test_reserved_threepid(self): self.auth_blocking._limit_usage_by_mau = True self.auth_blocking._max_mau_value = 1 - self.store.get_monthly_active_count = simple_async_mock(2) + self.store.get_monthly_active_count = AsyncMock(return_value=2) threepid = {"medium": "email", "address": "reserved@server.com"} unknown_threepid = {"medium": "email", "address": "unreserved@server.com"} self.auth_blocking._mau_limits_reserved_threepids = [threepid] diff --git a/tests/appservice/test_scheduler.py b/tests/appservice/test_scheduler.py index 55f0899bae7d..43281abb398b 100644 --- a/tests/appservice/test_scheduler.py +++ b/tests/appservice/test_scheduler.py @@ -11,7 +11,7 @@ # 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 unittest.mock import Mock +from unittest.mock import AsyncMock, Mock from twisted.internet import defer @@ -24,7 +24,6 @@ from synapse.logging.context import make_deferred_yieldable from tests import unittest -from tests.test_utils import simple_async_mock from ..utils import MockClock @@ -49,10 +48,12 @@ def test_single_service_up_txn_sent(self): txn = Mock(id=txn_id, service=service, events=events) # mock methods - self.store.get_appservice_state = simple_async_mock(ApplicationServiceState.UP) - txn.send = simple_async_mock(True) - txn.complete = simple_async_mock(True) - self.store.create_appservice_txn = simple_async_mock(txn) + self.store.get_appservice_state = AsyncMock( + return_value=ApplicationServiceState.UP + ) + txn.send = AsyncMock(return_value=True) + txn.complete = AsyncMock(return_value=True) + self.store.create_appservice_txn = AsyncMock(return_value=txn) # actual call self.successResultOf(defer.ensureDeferred(self.txnctrl.send(service, events))) @@ -70,10 +71,10 @@ def test_single_service_down(self): events = [Mock(), Mock()] txn = Mock(id="idhere", service=service, events=events) - self.store.get_appservice_state = simple_async_mock( - ApplicationServiceState.DOWN + self.store.get_appservice_state = AsyncMock( + return_value=ApplicationServiceState.DOWN ) - self.store.create_appservice_txn = simple_async_mock(txn) + self.store.create_appservice_txn = AsyncMock(return_value=txn) # actual call self.successResultOf(defer.ensureDeferred(self.txnctrl.send(service, events))) @@ -93,10 +94,12 @@ def test_single_service_up_txn_not_sent(self): txn = Mock(id=txn_id, service=service, events=events) # mock methods - self.store.get_appservice_state = simple_async_mock(ApplicationServiceState.UP) - self.store.set_appservice_state = simple_async_mock(True) - txn.send = simple_async_mock(False) # fails to send - self.store.create_appservice_txn = simple_async_mock(txn) + self.store.get_appservice_state = AsyncMock( + return_value=ApplicationServiceState.UP + ) + self.store.set_appservice_state = AsyncMock(return_value=True) + txn.send = AsyncMock(return_value=False) # fails to send + self.store.create_appservice_txn = AsyncMock(return_value=txn) # actual call self.successResultOf(defer.ensureDeferred(self.txnctrl.send(service, events))) @@ -119,7 +122,7 @@ def setUp(self): self.as_api = Mock() self.store = Mock() self.service = Mock() - self.callback = simple_async_mock() + self.callback = AsyncMock() self.recoverer = _Recoverer( clock=self.clock, as_api=self.as_api, @@ -141,8 +144,8 @@ def take_txn(*args, **kwargs): self.recoverer.recover() # shouldn't have called anything prior to waiting for exp backoff self.assertEquals(0, self.store.get_oldest_unsent_txn.call_count) - txn.send = simple_async_mock(True) - txn.complete = simple_async_mock(None) + txn.send = AsyncMock(return_value=True) + txn.complete = AsyncMock(return_value=None) # wait for exp backoff self.clock.advance_time(2) self.assertEquals(1, txn.send.call_count) @@ -167,8 +170,8 @@ def take_txn(*args, **kwargs): self.recoverer.recover() self.assertEquals(0, self.store.get_oldest_unsent_txn.call_count) - txn.send = simple_async_mock(False) - txn.complete = simple_async_mock(None) + txn.send = AsyncMock(return_value=False) + txn.complete = AsyncMock(return_value=None) self.clock.advance_time(2) self.assertEquals(1, txn.send.call_count) self.assertEquals(0, txn.complete.call_count) @@ -181,7 +184,7 @@ def take_txn(*args, **kwargs): self.assertEquals(3, txn.send.call_count) self.assertEquals(0, txn.complete.call_count) self.assertEquals(0, self.callback.call_count) - txn.send = simple_async_mock(True) # successfully send the txn + txn.send = AsyncMock(return_value=True) # successfully send the txn pop_txn = True # returns the txn the first time, then no more. self.clock.advance_time(16) self.assertEquals(1, txn.send.call_count) # new mock reset call count @@ -192,7 +195,7 @@ def take_txn(*args, **kwargs): class ApplicationServiceSchedulerQueuerTestCase(unittest.TestCase): def setUp(self): self.txn_ctrl = Mock() - self.txn_ctrl.send = simple_async_mock() + self.txn_ctrl.send = AsyncMock() self.queuer = _ServiceQueuer(self.txn_ctrl, MockClock()) def test_send_single_event_no_queue(self): diff --git a/tests/events/test_presence_router.py b/tests/events/test_presence_router.py index 3deb14c308b6..9fddaab765cd 100644 --- a/tests/events/test_presence_router.py +++ b/tests/events/test_presence_router.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from typing import Dict, Iterable, List, Optional, Set, Tuple, Union -from unittest.mock import Mock +from unittest.mock import AsyncMock, Mock import attr @@ -26,7 +26,6 @@ from synapse.types import JsonDict, StreamToken, create_requester from tests.handlers.test_sync import generate_sync_config -from tests.test_utils import simple_async_mock from tests.unittest import FederatingHomeserverTestCase, TestCase, override_config @@ -136,7 +135,7 @@ class PresenceRouterTestCase(FederatingHomeserverTestCase): def make_homeserver(self, reactor, clock): # Mock out the calls over federation. fed_transport_client = Mock(spec=["send_transaction"]) - fed_transport_client.send_transaction = simple_async_mock({}) + fed_transport_client.send_transaction = AsyncMock(return_value={}) hs = self.setup_test_homeserver( federation_transport_client=fed_transport_client, diff --git a/tests/handlers/test_cas.py b/tests/handlers/test_cas.py index 8705ff894343..c10bead0be55 100644 --- a/tests/handlers/test_cas.py +++ b/tests/handlers/test_cas.py @@ -11,11 +11,10 @@ # 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 unittest.mock import Mock +from unittest.mock import AsyncMock, Mock from synapse.handlers.cas import CasResponse -from tests.test_utils import simple_async_mock from tests.unittest import HomeserverTestCase, override_config # These are a few constants that are used as config parameters in the tests. @@ -56,7 +55,7 @@ def test_map_cas_user_to_user(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() cas_response = CasResponse("test_user", {}) request = _mock_request() @@ -84,7 +83,7 @@ def test_map_cas_user_to_existing_user(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() # Map a user via SSO. cas_response = CasResponse("test_user", {}) @@ -124,7 +123,7 @@ def test_map_cas_user_to_invalid_localpart(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() cas_response = CasResponse("föö", {}) request = _mock_request() @@ -155,7 +154,7 @@ def test_required_attributes(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() # The response doesn't have the proper userGroup or department. cas_response = CasResponse("test_user", {}) diff --git a/tests/handlers/test_oidc.py b/tests/handlers/test_oidc.py index cfe3de526682..65687d1c8351 100644 --- a/tests/handlers/test_oidc.py +++ b/tests/handlers/test_oidc.py @@ -13,7 +13,7 @@ # limitations under the License. import json import os -from unittest.mock import ANY, Mock, patch +from unittest.mock import ANY, AsyncMock, Mock, patch from urllib.parse import parse_qs, urlparse import pymacaroons @@ -23,7 +23,7 @@ from synapse.types import UserID from synapse.util.macaroons import get_value_from_macaroon -from tests.test_utils import FakeResponse, get_awaitable_result, simple_async_mock +from tests.test_utils import FakeResponse, get_awaitable_result from tests.unittest import HomeserverTestCase, override_config try: @@ -428,11 +428,11 @@ def test_callback(self): "username": username, } expected_user_id = "@%s:%s" % (username, self.hs.hostname) - self.provider._exchange_code = simple_async_mock(return_value=token) - self.provider._parse_id_token = simple_async_mock(return_value=userinfo) - self.provider._fetch_userinfo = simple_async_mock(return_value=userinfo) + self.provider._exchange_code = AsyncMock(return_value=token) + self.provider._parse_id_token = AsyncMock(return_value=userinfo) + self.provider._fetch_userinfo = AsyncMock(return_value=userinfo) auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() code = "code" state = "state" @@ -471,7 +471,7 @@ def test_callback(self): self.assertRenderedError("mapping_error") # Handle ID token errors - self.provider._parse_id_token = simple_async_mock(raises=Exception()) + self.provider._parse_id_token = AsyncMock(side_effect=Exception) self.get_success(self.handler.handle_oidc_callback(request)) self.assertRenderedError("invalid_token") @@ -486,7 +486,7 @@ def test_callback(self): "type": "bearer", "access_token": "access_token", } - self.provider._exchange_code = simple_async_mock(return_value=token) + self.provider._exchange_code = AsyncMock(return_value=token) self.get_success(self.handler.handle_oidc_callback(request)) auth_handler.complete_sso_login.assert_called_once_with( @@ -513,8 +513,8 @@ def test_callback(self): id_token = { "sid": "abcdefgh", } - self.provider._parse_id_token = simple_async_mock(return_value=id_token) - self.provider._exchange_code = simple_async_mock(return_value=token) + self.provider._parse_id_token = AsyncMock(return_value=id_token) + self.provider._exchange_code = AsyncMock(return_value=token) auth_handler.complete_sso_login.reset_mock() self.provider._fetch_userinfo.reset_mock() self.get_success(self.handler.handle_oidc_callback(request)) @@ -534,15 +534,15 @@ def test_callback(self): self.render_error.assert_not_called() # Handle userinfo fetching error - self.provider._fetch_userinfo = simple_async_mock(raises=Exception()) + self.provider._fetch_userinfo = AsyncMock(side_effect=Exception) self.get_success(self.handler.handle_oidc_callback(request)) self.assertRenderedError("fetch_error") # Handle code exchange failure from synapse.handlers.oidc import OidcError - self.provider._exchange_code = simple_async_mock( - raises=OidcError("invalid_request") + self.provider._exchange_code = AsyncMock( + side_effect=OidcError("invalid_request") ) self.get_success(self.handler.handle_oidc_callback(request)) self.assertRenderedError("invalid_request") @@ -597,7 +597,7 @@ def test_exchange_code(self): """Code exchange behaves correctly and handles various error scenarios.""" token = {"type": "bearer"} token_json = json.dumps(token).encode("utf-8") - self.http_client.request = simple_async_mock( + self.http_client.request = AsyncMock( return_value=FakeResponse(code=200, phrase=b"OK", body=token_json) ) code = "code" @@ -616,7 +616,7 @@ def test_exchange_code(self): self.assertEqual(args["redirect_uri"], [CALLBACK_URL]) # Test error handling - self.http_client.request = simple_async_mock( + self.http_client.request = AsyncMock( return_value=FakeResponse( code=400, phrase=b"Bad Request", @@ -630,7 +630,7 @@ def test_exchange_code(self): self.assertEqual(exc.value.error_description, "bar") # Internal server error with no JSON body - self.http_client.request = simple_async_mock( + self.http_client.request = AsyncMock( return_value=FakeResponse( code=500, phrase=b"Internal Server Error", @@ -641,7 +641,7 @@ def test_exchange_code(self): self.assertEqual(exc.value.error, "server_error") # Internal server error with JSON body - self.http_client.request = simple_async_mock( + self.http_client.request = AsyncMock( return_value=FakeResponse( code=500, phrase=b"Internal Server Error", @@ -653,7 +653,7 @@ def test_exchange_code(self): self.assertEqual(exc.value.error, "internal_server_error") # 4xx error without "error" field - self.http_client.request = simple_async_mock( + self.http_client.request = AsyncMock( return_value=FakeResponse( code=400, phrase=b"Bad request", @@ -664,7 +664,7 @@ def test_exchange_code(self): self.assertEqual(exc.value.error, "server_error") # 2xx error with "error" field - self.http_client.request = simple_async_mock( + self.http_client.request = AsyncMock( return_value=FakeResponse( code=200, phrase=b"OK", @@ -694,7 +694,7 @@ def test_exchange_code_jwt_key(self): from authlib.jose import jwt token = {"type": "bearer"} - self.http_client.request = simple_async_mock( + self.http_client.request = AsyncMock( return_value=FakeResponse( code=200, phrase=b"OK", body=json.dumps(token).encode("utf-8") ) @@ -747,7 +747,7 @@ def test_exchange_code_jwt_key(self): def test_exchange_code_no_auth(self): """Test that code exchange works with no client secret.""" token = {"type": "bearer"} - self.http_client.request = simple_async_mock( + self.http_client.request = AsyncMock( return_value=FakeResponse( code=200, phrase=b"OK", body=json.dumps(token).encode("utf-8") ) @@ -793,10 +793,10 @@ def test_extra_attributes(self): "username": "foo", "phone": "1234567", } - self.provider._exchange_code = simple_async_mock(return_value=token) - self.provider._parse_id_token = simple_async_mock(return_value=userinfo) + self.provider._exchange_code = AsyncMock(return_value=token) + self.provider._parse_id_token = AsyncMock(return_value=userinfo) auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() state = "state" client_redirect_url = "http://client/redirect" @@ -823,7 +823,7 @@ def test_extra_attributes(self): def test_map_userinfo_to_user(self): """Ensure that mapping the userinfo returned from a provider to an MXID works properly.""" auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() userinfo = { "sub": "test_user", @@ -882,7 +882,7 @@ def test_map_userinfo_to_existing_user(self): ) auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() # Map a user via SSO. userinfo = { @@ -997,7 +997,7 @@ def test_map_userinfo_to_invalid_localpart(self): def test_map_userinfo_to_user_retries(self): """The mapping provider can retry generating an MXID if the MXID is already in use.""" auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() store = self.hs.get_datastore() self.get_success( @@ -1081,7 +1081,7 @@ def test_null_localpart(self): def test_attribute_requirements(self): """The required attributes must be met from the OIDC userinfo response.""" auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() # userinfo lacking "test": "foobar" attribute should fail. userinfo = { @@ -1121,7 +1121,7 @@ def test_attribute_requirements(self): def test_attribute_requirements_contains(self): """Test that auth succeeds if userinfo attribute CONTAINS required value""" auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() # userinfo with "test": ["foobar", "foo", "bar"] attribute should succeed. userinfo = { "sub": "tester", @@ -1155,7 +1155,7 @@ def test_attribute_requirements_mismatch(self): or are non-string values. """ auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() # userinfo with "test": "not_foobar" attribute should fail userinfo = { "sub": "tester", @@ -1251,9 +1251,9 @@ async def _make_callback_with_userinfo( handler = hs.get_oidc_handler() provider = handler._providers["oidc"] - provider._exchange_code = simple_async_mock(return_value={"id_token": ""}) - provider._parse_id_token = simple_async_mock(return_value=userinfo) - provider._fetch_userinfo = simple_async_mock(return_value=userinfo) + provider._exchange_code = AsyncMock(return_value={"id_token": ""}) + provider._parse_id_token = AsyncMock(return_value=userinfo) + provider._fetch_userinfo = AsyncMock(return_value=userinfo) state = "state" session = handler._token_generator.generate_oidc_session_token( diff --git a/tests/handlers/test_saml.py b/tests/handlers/test_saml.py index 50551aa6e3c2..71d81dcbf217 100644 --- a/tests/handlers/test_saml.py +++ b/tests/handlers/test_saml.py @@ -13,13 +13,12 @@ # limitations under the License. from typing import Optional -from unittest.mock import Mock +from unittest.mock import AsyncMock, Mock import attr from synapse.api.errors import RedirectException -from tests.test_utils import simple_async_mock from tests.unittest import HomeserverTestCase, override_config # Check if we have the dependencies to run the tests. @@ -119,7 +118,7 @@ def test_map_saml_response_to_user(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() # send a mocked-up SAML response to the callback saml_response = FakeAuthnResponse({"uid": "test_user", "username": "test_user"}) @@ -149,7 +148,7 @@ def test_map_saml_response_to_existing_user(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() # Map a user via SSO. saml_response = FakeAuthnResponse( @@ -191,7 +190,7 @@ def test_map_saml_response_to_invalid_localpart(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() # mock out the error renderer too sso_handler = self.hs.get_sso_handler() @@ -212,7 +211,7 @@ def test_map_saml_response_to_user_retries(self): # stub out the auth handler and error renderer auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() sso_handler = self.hs.get_sso_handler() sso_handler.render_error = Mock(return_value=None) @@ -297,7 +296,7 @@ def test_attribute_requirements(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = simple_async_mock() + auth_handler.complete_sso_login = AsyncMock() # The response doesn't have the proper userGroup or department. saml_response = FakeAuthnResponse({"uid": "test_user", "username": "test_user"}) diff --git a/tests/module_api/test_api.py b/tests/module_api/test_api.py index d16cd141a750..e181eadc670f 100644 --- a/tests/module_api/test_api.py +++ b/tests/module_api/test_api.py @@ -11,7 +11,7 @@ # 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 unittest.mock import Mock +from unittest.mock import AsyncMock, Mock from twisted.internet import defer @@ -25,7 +25,6 @@ from tests.events.test_presence_router import send_presence_update, sync_presence from tests.replication._base import BaseMultiWorkerStreamTestCase -from tests.test_utils import simple_async_mock from tests.test_utils.event_injection import inject_member_event from tests.unittest import HomeserverTestCase, override_config from tests.utils import USE_POSTGRES_FOR_TESTS @@ -50,7 +49,7 @@ def prepare(self, reactor, clock, homeserver): def make_homeserver(self, reactor, clock): # Mock out the calls over federation. fed_transport_client = Mock(spec=["send_transaction"]) - fed_transport_client.send_transaction = simple_async_mock({}) + fed_transport_client.send_transaction = AsyncMock(return_value={}) return self.setup_test_homeserver( federation_transport_client=fed_transport_client, diff --git a/tests/test_utils/__init__.py b/tests/test_utils/__init__.py index 15ac2bfeba1e..81d40fb27fdf 100644 --- a/tests/test_utils/__init__.py +++ b/tests/test_utils/__init__.py @@ -87,16 +87,6 @@ def cleanup(): return cleanup -def simple_async_mock(return_value=None, raises=None) -> Mock: - # AsyncMock is not available in python3.5, this mimics part of its behaviour - async def cb(*args, **kwargs): - if raises: - raise raises - return return_value - - return Mock(side_effect=cb) - - @attr.s class FakeResponse: """A fake twisted.web.IResponse object From dec45f66349b6248cdfe2026fa92514d5ba8877d Mon Sep 17 00:00:00 2001 From: "Kai A. Hiller" Date: Wed, 15 Dec 2021 21:39:52 +0100 Subject: [PATCH 3/7] Add changelog entry --- changelog.d/11588.removal | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/11588.removal diff --git a/changelog.d/11588.removal b/changelog.d/11588.removal new file mode 100644 index 000000000000..f781021e11c7 --- /dev/null +++ b/changelog.d/11588.removal @@ -0,0 +1 @@ +Replace `mock` package by its standard library version. From 70959978c13395c1e20fb0317fbf755eaeb8b93f Mon Sep 17 00:00:00 2001 From: "Kai A. Hiller" Date: Wed, 15 Dec 2021 21:42:22 +0100 Subject: [PATCH 4/7] Remove unused import --- tests/test_utils/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_utils/__init__.py b/tests/test_utils/__init__.py index 81d40fb27fdf..7ab8c386a19f 100644 --- a/tests/test_utils/__init__.py +++ b/tests/test_utils/__init__.py @@ -20,7 +20,6 @@ from asyncio import Future from binascii import unhexlify from typing import Any, Awaitable, Callable, TypeVar -from unittest.mock import Mock import attr From 333456af41757d9916c5085f660297ab91d2b5cd Mon Sep 17 00:00:00 2001 From: "Kai A. Hiller" Date: Fri, 17 Dec 2021 09:17:40 +0100 Subject: [PATCH 5/7] Revert "Replace simple_async_mock with AsyncMock" This reverts commit c812db96257c1526c88c11110bec4045bf7cf24b. --- tests/api/test_auth.py | 79 +++++++++++++--------------- tests/appservice/test_scheduler.py | 43 +++++++-------- tests/events/test_presence_router.py | 5 +- tests/handlers/test_cas.py | 11 ++-- tests/handlers/test_oidc.py | 66 +++++++++++------------ tests/handlers/test_saml.py | 13 ++--- tests/module_api/test_api.py | 5 +- tests/test_utils/__init__.py | 11 ++++ 8 files changed, 121 insertions(+), 112 deletions(-) diff --git a/tests/api/test_auth.py b/tests/api/test_auth.py index 3ae054b72af0..a2dfa1ed0507 100644 --- a/tests/api/test_auth.py +++ b/tests/api/test_auth.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from unittest.mock import AsyncMock, Mock +from unittest.mock import Mock import pymacaroons @@ -30,6 +30,7 @@ from synapse.types import Requester from tests import unittest +from tests.test_utils import simple_async_mock from tests.unittest import override_config from tests.utils import mock_getRawHeaders @@ -52,15 +53,15 @@ def prepare(self, reactor, clock, hs): # this is overridden for the appservice tests self.store.get_app_service_by_token = Mock(return_value=None) - self.store.insert_client_ip = AsyncMock(return_value=None) - self.store.is_support_user = AsyncMock(return_value=False) + self.store.insert_client_ip = simple_async_mock(None) + self.store.is_support_user = simple_async_mock(False) def test_get_user_by_req_user_valid_token(self): user_info = TokenLookupResult( user_id=self.test_user, token_id=5, device_id="device" ) - self.store.get_user_by_access_token = AsyncMock(return_value=user_info) - self.store.mark_access_token_as_used = AsyncMock(return_value=None) + self.store.get_user_by_access_token = simple_async_mock(user_info) + self.store.mark_access_token_as_used = simple_async_mock(None) request = Mock(args={}) request.args[b"access_token"] = [self.test_token] @@ -69,7 +70,7 @@ def test_get_user_by_req_user_valid_token(self): self.assertEquals(requester.user.to_string(), self.test_user) def test_get_user_by_req_user_bad_token(self): - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_access_token = simple_async_mock(None) request = Mock(args={}) request.args[b"access_token"] = [self.test_token] @@ -82,7 +83,7 @@ def test_get_user_by_req_user_bad_token(self): def test_get_user_by_req_user_missing_token(self): user_info = TokenLookupResult(user_id=self.test_user, token_id=5) - self.store.get_user_by_access_token = AsyncMock(return_value=user_info) + self.store.get_user_by_access_token = simple_async_mock(user_info) request = Mock(args={}) request.requestHeaders.getRawHeaders = mock_getRawHeaders() @@ -97,7 +98,7 @@ def test_get_user_by_req_appservice_valid_token(self): token="foobar", url="a_url", sender=self.test_user, ip_range_whitelist=None ) self.store.get_app_service_by_token = Mock(return_value=app_service) - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_access_token = simple_async_mock(None) request = Mock(args={}) request.getClientIP.return_value = "127.0.0.1" @@ -116,7 +117,7 @@ def test_get_user_by_req_appservice_valid_token_good_ip(self): ip_range_whitelist=IPSet(["192.168/16"]), ) self.store.get_app_service_by_token = Mock(return_value=app_service) - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_access_token = simple_async_mock(None) request = Mock(args={}) request.getClientIP.return_value = "192.168.10.10" @@ -135,7 +136,7 @@ def test_get_user_by_req_appservice_valid_token_bad_ip(self): ip_range_whitelist=IPSet(["192.168/16"]), ) self.store.get_app_service_by_token = Mock(return_value=app_service) - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_access_token = simple_async_mock(None) request = Mock(args={}) request.getClientIP.return_value = "131.111.8.42" @@ -149,7 +150,7 @@ def test_get_user_by_req_appservice_valid_token_bad_ip(self): def test_get_user_by_req_appservice_bad_token(self): self.store.get_app_service_by_token = Mock(return_value=None) - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_access_token = simple_async_mock(None) request = Mock(args={}) request.args[b"access_token"] = [self.test_token] @@ -163,7 +164,7 @@ def test_get_user_by_req_appservice_bad_token(self): def test_get_user_by_req_appservice_missing_token(self): app_service = Mock(token="foobar", url="a_url", sender=self.test_user) self.store.get_app_service_by_token = Mock(return_value=app_service) - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_access_token = simple_async_mock(None) request = Mock(args={}) request.requestHeaders.getRawHeaders = mock_getRawHeaders() @@ -181,8 +182,8 @@ def test_get_user_by_req_appservice_valid_token_valid_user_id(self): app_service.is_interested_in_user = Mock(return_value=True) self.store.get_app_service_by_token = Mock(return_value=app_service) # This just needs to return a truth-y value. - self.store.get_user_by_id = AsyncMock(return_value={"is_guest": False}) - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_id = simple_async_mock({"is_guest": False}) + self.store.get_user_by_access_token = simple_async_mock(None) request = Mock(args={}) request.getClientIP.return_value = "127.0.0.1" @@ -201,7 +202,7 @@ def test_get_user_by_req_appservice_valid_token_bad_user_id(self): ) app_service.is_interested_in_user = Mock(return_value=False) self.store.get_app_service_by_token = Mock(return_value=app_service) - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_access_token = simple_async_mock(None) request = Mock(args={}) request.getClientIP.return_value = "127.0.0.1" @@ -225,10 +226,10 @@ def test_get_user_by_req_appservice_valid_token_valid_device_id(self): app_service.is_interested_in_user = Mock(return_value=True) self.store.get_app_service_by_token = Mock(return_value=app_service) # This just needs to return a truth-y value. - self.store.get_user_by_id = AsyncMock(return_value={"is_guest": False}) - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_id = simple_async_mock({"is_guest": False}) + self.store.get_user_by_access_token = simple_async_mock(None) # This also needs to just return a truth-y value - self.store.get_device = AsyncMock(return_value={"hidden": False}) + self.store.get_device = simple_async_mock({"hidden": False}) request = Mock(args={}) request.getClientIP.return_value = "127.0.0.1" @@ -257,10 +258,10 @@ def test_get_user_by_req_appservice_valid_token_invalid_device_id(self): app_service.is_interested_in_user = Mock(return_value=True) self.store.get_app_service_by_token = Mock(return_value=app_service) # This just needs to return a truth-y value. - self.store.get_user_by_id = AsyncMock(return_value={"is_guest": False}) - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_id = simple_async_mock({"is_guest": False}) + self.store.get_user_by_access_token = simple_async_mock(None) # This also needs to just return a falsey value - self.store.get_device = AsyncMock(return_value=None) + self.store.get_device = simple_async_mock(None) request = Mock(args={}) request.getClientIP.return_value = "127.0.0.1" @@ -274,10 +275,8 @@ def test_get_user_by_req_appservice_valid_token_invalid_device_id(self): self.assertEquals(failure.value.errcode, Codes.EXCLUSIVE) def test_get_user_from_macaroon(self): - self.store.get_user_by_access_token = AsyncMock( - return_value=TokenLookupResult( - user_id="@baldrick:matrix.org", device_id="device" - ) + self.store.get_user_by_access_token = simple_async_mock( + TokenLookupResult(user_id="@baldrick:matrix.org", device_id="device") ) user_id = "@baldrick:matrix.org" @@ -299,8 +298,8 @@ def test_get_user_from_macaroon(self): self.assertEqual(user_info.device_id, "device") def test_get_guest_user_from_macaroon(self): - self.store.get_user_by_id = AsyncMock(return_value={"is_guest": True}) - self.store.get_user_by_access_token = AsyncMock(return_value=None) + self.store.get_user_by_id = simple_async_mock({"is_guest": True}) + self.store.get_user_by_access_token = simple_async_mock(None) user_id = "@baldrick:matrix.org" macaroon = pymacaroons.Macaroon( @@ -330,7 +329,7 @@ def test_blocking_mau(self): self.auth_blocking._limit_usage_by_mau = True - self.store.get_monthly_active_count = AsyncMock(return_value=lots_of_users) + self.store.get_monthly_active_count = simple_async_mock(lots_of_users) e = self.get_failure(self.auth.check_auth_blocking(), ResourceLimitError) self.assertEquals(e.value.admin_contact, self.hs.config.server.admin_contact) @@ -338,24 +337,22 @@ def test_blocking_mau(self): self.assertEquals(e.value.code, 403) # Ensure does not throw an error - self.store.get_monthly_active_count = AsyncMock( - return_value=small_number_of_users - ) + self.store.get_monthly_active_count = simple_async_mock(small_number_of_users) self.get_success(self.auth.check_auth_blocking()) def test_blocking_mau__depending_on_user_type(self): self.auth_blocking._max_mau_value = 50 self.auth_blocking._limit_usage_by_mau = True - self.store.get_monthly_active_count = AsyncMock(return_value=100) + self.store.get_monthly_active_count = simple_async_mock(100) # Support users allowed self.get_success(self.auth.check_auth_blocking(user_type=UserTypes.SUPPORT)) - self.store.get_monthly_active_count = AsyncMock(return_value=100) + self.store.get_monthly_active_count = simple_async_mock(100) # Bots not allowed self.get_failure( self.auth.check_auth_blocking(user_type=UserTypes.BOT), ResourceLimitError ) - self.store.get_monthly_active_count = AsyncMock(return_value=100) + self.store.get_monthly_active_count = simple_async_mock(100) # Real users not allowed self.get_failure(self.auth.check_auth_blocking(), ResourceLimitError) @@ -364,9 +361,9 @@ def test_blocking_mau__appservice_requester_allowed_when_not_tracking_ips(self): self.auth_blocking._limit_usage_by_mau = True self.auth_blocking._track_appservice_user_ips = False - self.store.get_monthly_active_count = AsyncMock(return_value=100) - self.store.user_last_seen_monthly_active = AsyncMock(return_value=None) - self.store.is_trial_user = AsyncMock(return_value=False) + self.store.get_monthly_active_count = simple_async_mock(100) + self.store.user_last_seen_monthly_active = simple_async_mock() + self.store.is_trial_user = simple_async_mock() appservice = ApplicationService( "abcd", @@ -393,9 +390,9 @@ def test_blocking_mau__appservice_requester_disallowed_when_tracking_ips(self): self.auth_blocking._limit_usage_by_mau = True self.auth_blocking._track_appservice_user_ips = True - self.store.get_monthly_active_count = AsyncMock(return_value=100) - self.store.user_last_seen_monthly_active = AsyncMock(return_value=None) - self.store.is_trial_user = AsyncMock(return_value=False) + self.store.get_monthly_active_count = simple_async_mock(100) + self.store.user_last_seen_monthly_active = simple_async_mock() + self.store.is_trial_user = simple_async_mock() appservice = ApplicationService( "abcd", @@ -422,7 +419,7 @@ def test_blocking_mau__appservice_requester_disallowed_when_tracking_ips(self): def test_reserved_threepid(self): self.auth_blocking._limit_usage_by_mau = True self.auth_blocking._max_mau_value = 1 - self.store.get_monthly_active_count = AsyncMock(return_value=2) + self.store.get_monthly_active_count = simple_async_mock(2) threepid = {"medium": "email", "address": "reserved@server.com"} unknown_threepid = {"medium": "email", "address": "unreserved@server.com"} self.auth_blocking._mau_limits_reserved_threepids = [threepid] diff --git a/tests/appservice/test_scheduler.py b/tests/appservice/test_scheduler.py index 43281abb398b..55f0899bae7d 100644 --- a/tests/appservice/test_scheduler.py +++ b/tests/appservice/test_scheduler.py @@ -11,7 +11,7 @@ # 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 unittest.mock import AsyncMock, Mock +from unittest.mock import Mock from twisted.internet import defer @@ -24,6 +24,7 @@ from synapse.logging.context import make_deferred_yieldable from tests import unittest +from tests.test_utils import simple_async_mock from ..utils import MockClock @@ -48,12 +49,10 @@ def test_single_service_up_txn_sent(self): txn = Mock(id=txn_id, service=service, events=events) # mock methods - self.store.get_appservice_state = AsyncMock( - return_value=ApplicationServiceState.UP - ) - txn.send = AsyncMock(return_value=True) - txn.complete = AsyncMock(return_value=True) - self.store.create_appservice_txn = AsyncMock(return_value=txn) + self.store.get_appservice_state = simple_async_mock(ApplicationServiceState.UP) + txn.send = simple_async_mock(True) + txn.complete = simple_async_mock(True) + self.store.create_appservice_txn = simple_async_mock(txn) # actual call self.successResultOf(defer.ensureDeferred(self.txnctrl.send(service, events))) @@ -71,10 +70,10 @@ def test_single_service_down(self): events = [Mock(), Mock()] txn = Mock(id="idhere", service=service, events=events) - self.store.get_appservice_state = AsyncMock( - return_value=ApplicationServiceState.DOWN + self.store.get_appservice_state = simple_async_mock( + ApplicationServiceState.DOWN ) - self.store.create_appservice_txn = AsyncMock(return_value=txn) + self.store.create_appservice_txn = simple_async_mock(txn) # actual call self.successResultOf(defer.ensureDeferred(self.txnctrl.send(service, events))) @@ -94,12 +93,10 @@ def test_single_service_up_txn_not_sent(self): txn = Mock(id=txn_id, service=service, events=events) # mock methods - self.store.get_appservice_state = AsyncMock( - return_value=ApplicationServiceState.UP - ) - self.store.set_appservice_state = AsyncMock(return_value=True) - txn.send = AsyncMock(return_value=False) # fails to send - self.store.create_appservice_txn = AsyncMock(return_value=txn) + self.store.get_appservice_state = simple_async_mock(ApplicationServiceState.UP) + self.store.set_appservice_state = simple_async_mock(True) + txn.send = simple_async_mock(False) # fails to send + self.store.create_appservice_txn = simple_async_mock(txn) # actual call self.successResultOf(defer.ensureDeferred(self.txnctrl.send(service, events))) @@ -122,7 +119,7 @@ def setUp(self): self.as_api = Mock() self.store = Mock() self.service = Mock() - self.callback = AsyncMock() + self.callback = simple_async_mock() self.recoverer = _Recoverer( clock=self.clock, as_api=self.as_api, @@ -144,8 +141,8 @@ def take_txn(*args, **kwargs): self.recoverer.recover() # shouldn't have called anything prior to waiting for exp backoff self.assertEquals(0, self.store.get_oldest_unsent_txn.call_count) - txn.send = AsyncMock(return_value=True) - txn.complete = AsyncMock(return_value=None) + txn.send = simple_async_mock(True) + txn.complete = simple_async_mock(None) # wait for exp backoff self.clock.advance_time(2) self.assertEquals(1, txn.send.call_count) @@ -170,8 +167,8 @@ def take_txn(*args, **kwargs): self.recoverer.recover() self.assertEquals(0, self.store.get_oldest_unsent_txn.call_count) - txn.send = AsyncMock(return_value=False) - txn.complete = AsyncMock(return_value=None) + txn.send = simple_async_mock(False) + txn.complete = simple_async_mock(None) self.clock.advance_time(2) self.assertEquals(1, txn.send.call_count) self.assertEquals(0, txn.complete.call_count) @@ -184,7 +181,7 @@ def take_txn(*args, **kwargs): self.assertEquals(3, txn.send.call_count) self.assertEquals(0, txn.complete.call_count) self.assertEquals(0, self.callback.call_count) - txn.send = AsyncMock(return_value=True) # successfully send the txn + txn.send = simple_async_mock(True) # successfully send the txn pop_txn = True # returns the txn the first time, then no more. self.clock.advance_time(16) self.assertEquals(1, txn.send.call_count) # new mock reset call count @@ -195,7 +192,7 @@ def take_txn(*args, **kwargs): class ApplicationServiceSchedulerQueuerTestCase(unittest.TestCase): def setUp(self): self.txn_ctrl = Mock() - self.txn_ctrl.send = AsyncMock() + self.txn_ctrl.send = simple_async_mock() self.queuer = _ServiceQueuer(self.txn_ctrl, MockClock()) def test_send_single_event_no_queue(self): diff --git a/tests/events/test_presence_router.py b/tests/events/test_presence_router.py index 9fddaab765cd..3deb14c308b6 100644 --- a/tests/events/test_presence_router.py +++ b/tests/events/test_presence_router.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from typing import Dict, Iterable, List, Optional, Set, Tuple, Union -from unittest.mock import AsyncMock, Mock +from unittest.mock import Mock import attr @@ -26,6 +26,7 @@ from synapse.types import JsonDict, StreamToken, create_requester from tests.handlers.test_sync import generate_sync_config +from tests.test_utils import simple_async_mock from tests.unittest import FederatingHomeserverTestCase, TestCase, override_config @@ -135,7 +136,7 @@ class PresenceRouterTestCase(FederatingHomeserverTestCase): def make_homeserver(self, reactor, clock): # Mock out the calls over federation. fed_transport_client = Mock(spec=["send_transaction"]) - fed_transport_client.send_transaction = AsyncMock(return_value={}) + fed_transport_client.send_transaction = simple_async_mock({}) hs = self.setup_test_homeserver( federation_transport_client=fed_transport_client, diff --git a/tests/handlers/test_cas.py b/tests/handlers/test_cas.py index c10bead0be55..8705ff894343 100644 --- a/tests/handlers/test_cas.py +++ b/tests/handlers/test_cas.py @@ -11,10 +11,11 @@ # 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 unittest.mock import AsyncMock, Mock +from unittest.mock import Mock from synapse.handlers.cas import CasResponse +from tests.test_utils import simple_async_mock from tests.unittest import HomeserverTestCase, override_config # These are a few constants that are used as config parameters in the tests. @@ -55,7 +56,7 @@ def test_map_cas_user_to_user(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() cas_response = CasResponse("test_user", {}) request = _mock_request() @@ -83,7 +84,7 @@ def test_map_cas_user_to_existing_user(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() # Map a user via SSO. cas_response = CasResponse("test_user", {}) @@ -123,7 +124,7 @@ def test_map_cas_user_to_invalid_localpart(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() cas_response = CasResponse("föö", {}) request = _mock_request() @@ -154,7 +155,7 @@ def test_required_attributes(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() # The response doesn't have the proper userGroup or department. cas_response = CasResponse("test_user", {}) diff --git a/tests/handlers/test_oidc.py b/tests/handlers/test_oidc.py index 65687d1c8351..cfe3de526682 100644 --- a/tests/handlers/test_oidc.py +++ b/tests/handlers/test_oidc.py @@ -13,7 +13,7 @@ # limitations under the License. import json import os -from unittest.mock import ANY, AsyncMock, Mock, patch +from unittest.mock import ANY, Mock, patch from urllib.parse import parse_qs, urlparse import pymacaroons @@ -23,7 +23,7 @@ from synapse.types import UserID from synapse.util.macaroons import get_value_from_macaroon -from tests.test_utils import FakeResponse, get_awaitable_result +from tests.test_utils import FakeResponse, get_awaitable_result, simple_async_mock from tests.unittest import HomeserverTestCase, override_config try: @@ -428,11 +428,11 @@ def test_callback(self): "username": username, } expected_user_id = "@%s:%s" % (username, self.hs.hostname) - self.provider._exchange_code = AsyncMock(return_value=token) - self.provider._parse_id_token = AsyncMock(return_value=userinfo) - self.provider._fetch_userinfo = AsyncMock(return_value=userinfo) + self.provider._exchange_code = simple_async_mock(return_value=token) + self.provider._parse_id_token = simple_async_mock(return_value=userinfo) + self.provider._fetch_userinfo = simple_async_mock(return_value=userinfo) auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() code = "code" state = "state" @@ -471,7 +471,7 @@ def test_callback(self): self.assertRenderedError("mapping_error") # Handle ID token errors - self.provider._parse_id_token = AsyncMock(side_effect=Exception) + self.provider._parse_id_token = simple_async_mock(raises=Exception()) self.get_success(self.handler.handle_oidc_callback(request)) self.assertRenderedError("invalid_token") @@ -486,7 +486,7 @@ def test_callback(self): "type": "bearer", "access_token": "access_token", } - self.provider._exchange_code = AsyncMock(return_value=token) + self.provider._exchange_code = simple_async_mock(return_value=token) self.get_success(self.handler.handle_oidc_callback(request)) auth_handler.complete_sso_login.assert_called_once_with( @@ -513,8 +513,8 @@ def test_callback(self): id_token = { "sid": "abcdefgh", } - self.provider._parse_id_token = AsyncMock(return_value=id_token) - self.provider._exchange_code = AsyncMock(return_value=token) + self.provider._parse_id_token = simple_async_mock(return_value=id_token) + self.provider._exchange_code = simple_async_mock(return_value=token) auth_handler.complete_sso_login.reset_mock() self.provider._fetch_userinfo.reset_mock() self.get_success(self.handler.handle_oidc_callback(request)) @@ -534,15 +534,15 @@ def test_callback(self): self.render_error.assert_not_called() # Handle userinfo fetching error - self.provider._fetch_userinfo = AsyncMock(side_effect=Exception) + self.provider._fetch_userinfo = simple_async_mock(raises=Exception()) self.get_success(self.handler.handle_oidc_callback(request)) self.assertRenderedError("fetch_error") # Handle code exchange failure from synapse.handlers.oidc import OidcError - self.provider._exchange_code = AsyncMock( - side_effect=OidcError("invalid_request") + self.provider._exchange_code = simple_async_mock( + raises=OidcError("invalid_request") ) self.get_success(self.handler.handle_oidc_callback(request)) self.assertRenderedError("invalid_request") @@ -597,7 +597,7 @@ def test_exchange_code(self): """Code exchange behaves correctly and handles various error scenarios.""" token = {"type": "bearer"} token_json = json.dumps(token).encode("utf-8") - self.http_client.request = AsyncMock( + self.http_client.request = simple_async_mock( return_value=FakeResponse(code=200, phrase=b"OK", body=token_json) ) code = "code" @@ -616,7 +616,7 @@ def test_exchange_code(self): self.assertEqual(args["redirect_uri"], [CALLBACK_URL]) # Test error handling - self.http_client.request = AsyncMock( + self.http_client.request = simple_async_mock( return_value=FakeResponse( code=400, phrase=b"Bad Request", @@ -630,7 +630,7 @@ def test_exchange_code(self): self.assertEqual(exc.value.error_description, "bar") # Internal server error with no JSON body - self.http_client.request = AsyncMock( + self.http_client.request = simple_async_mock( return_value=FakeResponse( code=500, phrase=b"Internal Server Error", @@ -641,7 +641,7 @@ def test_exchange_code(self): self.assertEqual(exc.value.error, "server_error") # Internal server error with JSON body - self.http_client.request = AsyncMock( + self.http_client.request = simple_async_mock( return_value=FakeResponse( code=500, phrase=b"Internal Server Error", @@ -653,7 +653,7 @@ def test_exchange_code(self): self.assertEqual(exc.value.error, "internal_server_error") # 4xx error without "error" field - self.http_client.request = AsyncMock( + self.http_client.request = simple_async_mock( return_value=FakeResponse( code=400, phrase=b"Bad request", @@ -664,7 +664,7 @@ def test_exchange_code(self): self.assertEqual(exc.value.error, "server_error") # 2xx error with "error" field - self.http_client.request = AsyncMock( + self.http_client.request = simple_async_mock( return_value=FakeResponse( code=200, phrase=b"OK", @@ -694,7 +694,7 @@ def test_exchange_code_jwt_key(self): from authlib.jose import jwt token = {"type": "bearer"} - self.http_client.request = AsyncMock( + self.http_client.request = simple_async_mock( return_value=FakeResponse( code=200, phrase=b"OK", body=json.dumps(token).encode("utf-8") ) @@ -747,7 +747,7 @@ def test_exchange_code_jwt_key(self): def test_exchange_code_no_auth(self): """Test that code exchange works with no client secret.""" token = {"type": "bearer"} - self.http_client.request = AsyncMock( + self.http_client.request = simple_async_mock( return_value=FakeResponse( code=200, phrase=b"OK", body=json.dumps(token).encode("utf-8") ) @@ -793,10 +793,10 @@ def test_extra_attributes(self): "username": "foo", "phone": "1234567", } - self.provider._exchange_code = AsyncMock(return_value=token) - self.provider._parse_id_token = AsyncMock(return_value=userinfo) + self.provider._exchange_code = simple_async_mock(return_value=token) + self.provider._parse_id_token = simple_async_mock(return_value=userinfo) auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() state = "state" client_redirect_url = "http://client/redirect" @@ -823,7 +823,7 @@ def test_extra_attributes(self): def test_map_userinfo_to_user(self): """Ensure that mapping the userinfo returned from a provider to an MXID works properly.""" auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() userinfo = { "sub": "test_user", @@ -882,7 +882,7 @@ def test_map_userinfo_to_existing_user(self): ) auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() # Map a user via SSO. userinfo = { @@ -997,7 +997,7 @@ def test_map_userinfo_to_invalid_localpart(self): def test_map_userinfo_to_user_retries(self): """The mapping provider can retry generating an MXID if the MXID is already in use.""" auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() store = self.hs.get_datastore() self.get_success( @@ -1081,7 +1081,7 @@ def test_null_localpart(self): def test_attribute_requirements(self): """The required attributes must be met from the OIDC userinfo response.""" auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() # userinfo lacking "test": "foobar" attribute should fail. userinfo = { @@ -1121,7 +1121,7 @@ def test_attribute_requirements(self): def test_attribute_requirements_contains(self): """Test that auth succeeds if userinfo attribute CONTAINS required value""" auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() # userinfo with "test": ["foobar", "foo", "bar"] attribute should succeed. userinfo = { "sub": "tester", @@ -1155,7 +1155,7 @@ def test_attribute_requirements_mismatch(self): or are non-string values. """ auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() # userinfo with "test": "not_foobar" attribute should fail userinfo = { "sub": "tester", @@ -1251,9 +1251,9 @@ async def _make_callback_with_userinfo( handler = hs.get_oidc_handler() provider = handler._providers["oidc"] - provider._exchange_code = AsyncMock(return_value={"id_token": ""}) - provider._parse_id_token = AsyncMock(return_value=userinfo) - provider._fetch_userinfo = AsyncMock(return_value=userinfo) + provider._exchange_code = simple_async_mock(return_value={"id_token": ""}) + provider._parse_id_token = simple_async_mock(return_value=userinfo) + provider._fetch_userinfo = simple_async_mock(return_value=userinfo) state = "state" session = handler._token_generator.generate_oidc_session_token( diff --git a/tests/handlers/test_saml.py b/tests/handlers/test_saml.py index 71d81dcbf217..50551aa6e3c2 100644 --- a/tests/handlers/test_saml.py +++ b/tests/handlers/test_saml.py @@ -13,12 +13,13 @@ # limitations under the License. from typing import Optional -from unittest.mock import AsyncMock, Mock +from unittest.mock import Mock import attr from synapse.api.errors import RedirectException +from tests.test_utils import simple_async_mock from tests.unittest import HomeserverTestCase, override_config # Check if we have the dependencies to run the tests. @@ -118,7 +119,7 @@ def test_map_saml_response_to_user(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() # send a mocked-up SAML response to the callback saml_response = FakeAuthnResponse({"uid": "test_user", "username": "test_user"}) @@ -148,7 +149,7 @@ def test_map_saml_response_to_existing_user(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() # Map a user via SSO. saml_response = FakeAuthnResponse( @@ -190,7 +191,7 @@ def test_map_saml_response_to_invalid_localpart(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() # mock out the error renderer too sso_handler = self.hs.get_sso_handler() @@ -211,7 +212,7 @@ def test_map_saml_response_to_user_retries(self): # stub out the auth handler and error renderer auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() sso_handler = self.hs.get_sso_handler() sso_handler.render_error = Mock(return_value=None) @@ -296,7 +297,7 @@ def test_attribute_requirements(self): # stub out the auth handler auth_handler = self.hs.get_auth_handler() - auth_handler.complete_sso_login = AsyncMock() + auth_handler.complete_sso_login = simple_async_mock() # The response doesn't have the proper userGroup or department. saml_response = FakeAuthnResponse({"uid": "test_user", "username": "test_user"}) diff --git a/tests/module_api/test_api.py b/tests/module_api/test_api.py index e181eadc670f..d16cd141a750 100644 --- a/tests/module_api/test_api.py +++ b/tests/module_api/test_api.py @@ -11,7 +11,7 @@ # 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 unittest.mock import AsyncMock, Mock +from unittest.mock import Mock from twisted.internet import defer @@ -25,6 +25,7 @@ from tests.events.test_presence_router import send_presence_update, sync_presence from tests.replication._base import BaseMultiWorkerStreamTestCase +from tests.test_utils import simple_async_mock from tests.test_utils.event_injection import inject_member_event from tests.unittest import HomeserverTestCase, override_config from tests.utils import USE_POSTGRES_FOR_TESTS @@ -49,7 +50,7 @@ def prepare(self, reactor, clock, homeserver): def make_homeserver(self, reactor, clock): # Mock out the calls over federation. fed_transport_client = Mock(spec=["send_transaction"]) - fed_transport_client.send_transaction = AsyncMock(return_value={}) + fed_transport_client.send_transaction = simple_async_mock({}) return self.setup_test_homeserver( federation_transport_client=fed_transport_client, diff --git a/tests/test_utils/__init__.py b/tests/test_utils/__init__.py index 7ab8c386a19f..15ac2bfeba1e 100644 --- a/tests/test_utils/__init__.py +++ b/tests/test_utils/__init__.py @@ -20,6 +20,7 @@ from asyncio import Future from binascii import unhexlify from typing import Any, Awaitable, Callable, TypeVar +from unittest.mock import Mock import attr @@ -86,6 +87,16 @@ def cleanup(): return cleanup +def simple_async_mock(return_value=None, raises=None) -> Mock: + # AsyncMock is not available in python3.5, this mimics part of its behaviour + async def cb(*args, **kwargs): + if raises: + raise raises + return return_value + + return Mock(side_effect=cb) + + @attr.s class FakeResponse: """A fake twisted.web.IResponse object From dac50aac7d501ecca832f88beb41dfdfdb756a85 Mon Sep 17 00:00:00 2001 From: "Kai A. Hiller" Date: Fri, 17 Dec 2021 09:17:08 +0100 Subject: [PATCH 6/7] Replace remaining non-std Mock --- tests/storage/test_background_update.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/storage/test_background_update.py b/tests/storage/test_background_update.py index 542b70a1ee6d..79414f886db1 100644 --- a/tests/storage/test_background_update.py +++ b/tests/storage/test_background_update.py @@ -19,7 +19,7 @@ from synapse.storage.background_updates import BackgroundUpdater from tests import unittest -from tests.test_utils import make_awaitable +from tests.test_utils import make_awaitable, simple_async_mock class BackgroundUpdateTestCase(unittest.HomeserverTestCase): @@ -115,14 +115,15 @@ def prepare(self, reactor, clock, homeserver): ) # Mock out the AsyncContextManager - self._update_ctx_manager = Mock(spec=["__aenter__", "__aexit__"]) - self._update_ctx_manager.__aenter__ = Mock( - return_value=make_awaitable(None), - ) - self._update_ctx_manager.__aexit__ = Mock(return_value=make_awaitable(None)) + class MockCM: + pass + + self._update_ctx_manager = MockCM + self._update_ctx_manager.__aenter__ = simple_async_mock(return_value=None) + self._update_ctx_manager.__aexit__ = simple_async_mock(return_value=None) # Mock out the `update_handler` callback - self._on_update = Mock(return_value=self._update_ctx_manager) + self._on_update = Mock(return_value=self._update_ctx_manager()) # Define a default batch size value that's not the same as the internal default # value (100). From fba02f15152d9d0f22aef04e8f9d32f6c0b57959 Mon Sep 17 00:00:00 2001 From: "Kai A. Hiller" Date: Fri, 17 Dec 2021 21:17:03 +0100 Subject: [PATCH 7/7] MockCM: Define methods inside class declaration --- tests/storage/test_background_update.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/storage/test_background_update.py b/tests/storage/test_background_update.py index 79414f886db1..6156dfac4e58 100644 --- a/tests/storage/test_background_update.py +++ b/tests/storage/test_background_update.py @@ -116,11 +116,10 @@ def prepare(self, reactor, clock, homeserver): # Mock out the AsyncContextManager class MockCM: - pass + __aenter__ = simple_async_mock(return_value=None) + __aexit__ = simple_async_mock(return_value=None) self._update_ctx_manager = MockCM - self._update_ctx_manager.__aenter__ = simple_async_mock(return_value=None) - self._update_ctx_manager.__aexit__ = simple_async_mock(return_value=None) # Mock out the `update_handler` callback self._on_update = Mock(return_value=self._update_ctx_manager())