Update tests to run with MAS module variant

We now run the standard battery of tests with a MAS-enabled module. Some
minimal adjustment was needed to check MAS-specific outputs.
This commit is contained in:
Andrew Morgan
2026-01-16 19:20:13 +00:00
parent 55ca2be0f6
commit 41922415ba
4 changed files with 119 additions and 31 deletions
@@ -30,6 +30,7 @@ dev =
twisted
aiounittest
coverage
parameterized
# for type checking
mypy == 1.10.0
pydantic == 2.4.2
@@ -9,8 +9,8 @@
import sqlite3
from asyncio import Future
from typing import Any, Awaitable, Callable, Dict, Tuple, TypeVar
from unittest.mock import Mock
from typing import Any, Awaitable, Callable, Dict, List, Tuple, TypeVar
from unittest.mock import AsyncMock, Mock
from synapse.http.client import SimpleHttpClient
from synapse.module_api import ModuleApi
@@ -81,6 +81,20 @@ def make_awaitable(result: TV) -> Awaitable[TV]:
return future
def set_async_return_value(target: Any, value: Any) -> None:
if isinstance(target, AsyncMock):
target.return_value = value
else:
target.return_value = make_awaitable(value)
def set_async_side_effect(target: Any, values: List[Any]) -> None:
if isinstance(target, AsyncMock):
target.side_effect = values
else:
target.side_effect = [make_awaitable(value) for value in values]
def get_qualified_user_id(username: str) -> str:
return f"@{username}:matrix.local"
@@ -129,6 +143,17 @@ def create_module(
return module, module_api, store
def mas_config_override() -> Dict[str, Any]:
return {
"mas": {
"admin_api_base_url": "https://mas.example.org",
"oauth_base_url": "https://oauth.mas.example.org",
"client_id": "client-id",
"client_secret": "client-secret",
},
}
def _setup_db(conn: sqlite3.Connection) -> None:
conn.execute("CREATE TABLE access_tokens(user_id text, token text)")
conn.execute(
@@ -7,17 +7,20 @@
# Originally licensed under the Apache License, Version 2.0:
# <http://www.apache.org/licenses/LICENSE-2.0>.
from typing import Tuple
from unittest.mock import Mock
import aiounittest
from parameterized import parameterized_class # type: ignore[import-untyped]
from synapse.module_api import ProfileInfo, UserProfile
from synapse.module_api.errors import ConfigError
from synapse.types import UserID
from synapse_guest_module.config import GuestModuleConfig, MasConfig
from synapse_guest_module.guest_module import GuestModule
from tests import create_module
from tests import SQLiteStore, create_module, mas_config_override
class GuestModuleTest(aiounittest.AsyncTestCase):
class GuestModuleConfigTest(aiounittest.AsyncTestCase):
async def test_parse_config_empty(self) -> None:
config = GuestModule.parse_config({})
@@ -121,8 +124,20 @@ class GuestModuleTest(aiounittest.AsyncTestCase):
}
)
@parameterized_class(
("variant", "config_override"),
[
("synapse", None),
("mas", mas_config_override()),
],
)
class GuestModuleRuntimeTest(aiounittest.AsyncTestCase):
def create_module(self) -> Tuple[GuestModule, Mock, SQLiteStore]:
return create_module(self.config_override)
async def test_profile_update_no_guest(self) -> None:
module, module_api, _ = create_module()
module, module_api, _ = self.create_module()
await module.profile_update(
"@my-user:matrix.local",
@@ -134,7 +149,7 @@ class GuestModuleTest(aiounittest.AsyncTestCase):
module_api.set_displayname.assert_not_called()
async def test_profile_update_guest_keep(self) -> None:
module, module_api, _ = create_module()
module, module_api, _ = self.create_module()
await module.profile_update(
"@guest-asdf:matrix.local",
@@ -146,7 +161,7 @@ class GuestModuleTest(aiounittest.AsyncTestCase):
module_api.set_displayname.assert_not_called()
async def test_profile_update_guest_add_and_trim(self) -> None:
module, module_api, _ = create_module()
module, module_api, _ = self.create_module()
await module.profile_update(
"@guest-asdf:matrix.local",
@@ -161,7 +176,7 @@ class GuestModuleTest(aiounittest.AsyncTestCase):
)
async def test_callback_user_may_create_room_no_guest(self) -> None:
module, _, _ = create_module()
module, _, _ = self.create_module()
allow = await module.callback_user_may_create_room(
"@my-user:matrix.local",
@@ -170,7 +185,7 @@ class GuestModuleTest(aiounittest.AsyncTestCase):
self.assertTrue(allow)
async def test_callback_user_may_create_room_guest(self) -> None:
module, _, _ = create_module()
module, _, _ = self.create_module()
allow = await module.callback_user_may_create_room(
"@guest-asdf:matrix.local",
@@ -179,7 +194,7 @@ class GuestModuleTest(aiounittest.AsyncTestCase):
self.assertFalse(allow)
async def test_callback_user_may_invite_no_guest(self) -> None:
module, _, _ = create_module()
module, _, _ = self.create_module()
allow = await module.callback_user_may_invite(
"@my-user:matrix.local",
@@ -190,7 +205,7 @@ class GuestModuleTest(aiounittest.AsyncTestCase):
self.assertTrue(allow)
async def test_callback_user_may_invite_guest(self) -> None:
module, _, _ = create_module()
module, _, _ = self.create_module()
allow = await module.callback_user_may_invite(
"@guest-asdf:matrix.local",
@@ -201,7 +216,7 @@ class GuestModuleTest(aiounittest.AsyncTestCase):
self.assertFalse(allow)
async def test_callback_check_username_for_spam_no_guest(self) -> None:
module, _, _ = create_module()
module, _, _ = self.create_module()
allow = await module.callback_check_username_for_spam(
UserProfile(
@@ -214,7 +229,7 @@ class GuestModuleTest(aiounittest.AsyncTestCase):
self.assertFalse(allow)
async def test_callback_check_username_for_spam_guest(self) -> None:
module, _, _ = create_module()
module, _, _ = self.create_module()
allow = await module.callback_check_username_for_spam(
UserProfile(
@@ -8,19 +8,38 @@
# <http://www.apache.org/licenses/LICENSE-2.0>.
import io
from typing import cast
from unittest.mock import ANY
from typing import Tuple, cast
from unittest.mock import ANY, Mock
import aiounittest
from parameterized import parameterized_class # type: ignore[import-untyped]
from twisted.web.server import Request
from twisted.web.test.requesthelper import DummyRequest
from synapse_guest_module import GuestModule
from tests import create_module, make_awaitable
from tests import (
SQLiteStore,
create_module,
make_awaitable,
mas_config_override,
set_async_return_value,
set_async_side_effect,
)
@parameterized_class(
("variant", "config_override"),
[
("synapse", None),
("mas", mas_config_override()),
],
)
class GuestUserReaperTest(aiounittest.AsyncTestCase):
def create_module(self) -> Tuple[GuestModule, Mock, SQLiteStore]:
return create_module(self.config_override)
async def test_async_render_POST_missing_displayname(self) -> None:
module, _, _ = create_module()
module, _, _ = self.create_module()
request = cast(Request, DummyRequest([]))
request.content = io.BytesIO(b"{}")
@@ -33,7 +52,7 @@ class GuestUserReaperTest(aiounittest.AsyncTestCase):
)
async def test_async_render_POST_empty_displayname(self) -> None:
module, _, _ = create_module()
module, _, _ = self.create_module()
request = cast(Request, DummyRequest([]))
request.content = io.BytesIO(b'{"displayname":" "}')
@@ -46,7 +65,7 @@ class GuestUserReaperTest(aiounittest.AsyncTestCase):
)
async def test_async_render_POST_no_free_username(self) -> None:
module, module_api, _ = create_module()
module, module_api, _ = self.create_module()
request = cast(Request, DummyRequest([]))
request.content = io.BytesIO(b'{"displayname":"My Name"}')
@@ -63,24 +82,52 @@ class GuestUserReaperTest(aiounittest.AsyncTestCase):
self.assertEqual(module_api.check_user_exists.call_count, 10)
async def test_async_render_POST_success(self) -> None:
module, module_api, _ = create_module()
module, module_api, _ = self.create_module()
request = cast(Request, DummyRequest([]))
request.content = io.BytesIO(b'{"displayname":"My Name "}')
if self.config_override is not None:
set_async_return_value(
module_api.http_client.post_urlencoded_get_json,
{"access_token": "mas_admin_token"},
)
set_async_side_effect(
module_api.http_client.post_json_get_json,
[
{"data": {"id": "mas-user-id"}},
{
"data": {
"id": "MASDEVICE",
"attributes": {"access_token": "mas_access_token"},
}
},
],
)
status, response = await module.registration_servlet._async_render_POST(request)
self.assertEqual(status, 201)
self.assertRegex(response.pop("userId"), r"^@guest-[A-Za-z0-9]+:matrix.local$")
self.assertDictEqual(
response,
{
"accessToken": "syn_registered_token",
"deviceId": "DEVICEID",
"homeserverUrl": "https://matrix.local:1234/",
# "userId" was already checked by self.assertRegex and was removed from the object
},
)
module_api.register_user.assert_called_with(ANY, "My Name (Guest)")
if self.config_override is None:
self.assertDictEqual(
response,
{
"accessToken": "syn_registered_token",
"deviceId": "DEVICEID",
"homeserverUrl": "https://matrix.local:1234/",
# "userId" was already checked by self.assertRegex and was removed from the object
},
)
module_api.register_user.assert_called_with(ANY, "My Name (Guest)")
else:
self.assertDictEqual(
response,
{
"accessToken": "mas_access_token",
"deviceId": "MASDEVICE",
"homeserverUrl": "https://matrix.local:1234/",
# "userId" was already checked by self.assertRegex and was removed from the object
},
)