def test_matrix_nio_backend_handle_unsupported_message(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) backend.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") backend.client.rooms = { "test_room": "Test Room", "other_test_room": "Test Room" } message_body = "Test message" test_message = RoomMessageEmote.from_dict({ "content": { "body": message_body, "msgtype": "m.emote" }, "event_id": "$15163623196QOZxj:localhost", "origin_server_ts": 1516362319505, "room_id": "!SVkFJHzfwvuaIEawgC:localhost", "sender": "@example:localhost", "type": "m.room.message", "unsigned": { "age": 43464955731 }, "user_id": "@example:localhost", "age": 43464955731 }) test_room = nio.MatrixRoom("test_room", "test_user") test_message.to = test_room callback = mock.Mock() ErrBot.callback_message = callback backend.handle_message(test_room, test_message) callback.assert_not_called()
def test_matrix_nio_backend_serve_once_not_logged_in_has_synced(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) backend.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") backend.has_synced = True user_id = "@example:localhost" login_response = LoginResponse.from_dict({ "user_id": user_id, "device_id": "device_id", "access_token": "12345", }) login_response_mock = mock.Mock( return_value=aiounittest.futurized(login_response)) backend.client.login_raw = login_response_mock test_name = "Test Name" backend.client.get_profile = mock.Mock( return_value=aiounittest.futurized( ProfileGetResponse.from_dict( { "displayname": test_name, "avatar_url": "http://test.org/avatar.png" }))) sync_forever_mock = mock.Mock(return_value=aiounittest.futurized(True)) backend.client.sync_forever = sync_forever_mock backend.serve_once() sync_forever_mock.assert_called_once_with(30000, full_state=True) backend.client.get_profile.assert_called_once_with(user_id) login_response_mock.assert_called_once_with( self.bot_config.BOT_IDENTITY["auth_dict"])
async def test_matrix_nio_backend_send_message_error(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) test_server = "test.matrix.org" test_user = f"@test_user:{test_server}" event_id = "1234567890" room_id = "test_room" backend.client = nio.AsyncClient(test_server, user=test_user, device_id="test_device") backend.client.rooms = { "test_room": "Test Room", "other_test_room": "Test Room" } backend.client.room_send = mock.Mock( return_value=aiounittest.futurized( ErrorResponse.from_dict({ "errcode": "ERROR_SENDING_MESSAGE", "error": "Error sending message", "retry_after_ms": 10000 }))) message_text = "Test message" test_message = Message( message_text, matrix_nio.MatrixNioPerson("an_id", client=backend.client, emails=["*****@*****.**"], full_name="")) test_message.to = matrix_nio.MatrixNioRoom("test_room", client=backend.client, title="A title") test_message.to.room = "test_room" with self.assertRaises(ValueError): result = await backend._send_message(test_message) backend.client.room_send.assert_called_once()
async def test_github_notification(self): """Send a mock github webhook, and check the result.""" messages = [] client = nio.AsyncClient(MATRIX_URL, MATRIX_ID) await client.login(MATRIX_PW) room = await client.room_create() with open("tests/example_github_push.json", "rb") as f: example_github_push = f.read().strip() self.assertEqual( httpx.post( f"{BOT_URL}/{room.room_id}", params={ "formatter": "github", }, content=example_github_push, headers=headers(event="something else"), ).json(), {"status": 200, "ret": "OK"}, ) sync = await client.sync() messages = await client.room_messages(room.room_id, sync.next_batch) await client.close() message = messages.chunk[0] self.assertEqual(message.sender, FULL_ID) self.assertEqual( message.formatted_body, "<p>notification from github</p>", )
async def test_grafana_body(self): """Send a markdown message, and check the result.""" messages = [] client = nio.AsyncClient(MATRIX_URL, MATRIX_ID) await client.login(MATRIX_PW) room = await client.room_create() with open("tests/example_grafana.json") as f: example_grafana_request = f.read() self.assertEqual( httpx.post( f"{BOT_URL}/{room.room_id}", params={ "formatter": "grafana", "key": KEY }, content=example_grafana_request, ).json(), { "status": 200, "ret": "OK" }, ) sync = await client.sync() messages = await client.room_messages(room.room_id, sync.next_batch) await client.close() message = messages.chunk[0] self.assertEqual(message.sender, FULL_ID) self.assertEqual( message.body, "#### [Alerting] Panel Title alert\nNotification Message\n\n* Count: 1\n", )
def setUp(self) -> None: self.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") self.owner = "an_owner" self.room_id = "test_room" self.matrix_room1 = nio.MatrixRoom(self.owner, self.room_id) self.client.rooms = { "test_room": self.matrix_room1, "other_test_room": "also_empty_room" } self.subject = "test_room" self.title = "A title" self.topic = "a_topic" self.display_name = "a_display_name" self.room1 = matrix_nio.MatrixNioRoom(self.room_id, client=self.client, title=self.title, subject=self.subject) self.users = [ MatrixUser("12345", display_name="Charles de Gaulle"), MatrixUser("54321", display_name="Georges Pompidou") ] self.occupants = [ matrix_nio.MatrixNioRoomOccupant("12345", "Charles de Gaulle", self.client), matrix_nio.MatrixNioRoomOccupant("54321", "Georges Pompidou", self.client) ] self.room1.matrix_room.users = self.users self.room1.matrix_room.own_user_id = self.owner self.room1.matrix_room.topic = self.topic self.room1.matrix_room.name = self.display_name
async def run(args): profile = args.config client = nio.AsyncClient(profile['server'], profile['user']) if args.state: state = args.state client.access_token = state['access_token'] client.user_id = state['user_id'] client.device_id = state['device_id'] else: r = await client.login(profile['password']) raise_for_response(r) if args.store_state: update_state(client, args.state_filename, args.profile) if args.user: room = await do_with_relogin(client, args, private_room, client, args.user) if not room: raise RuntimeError( f'Could not find private direct message room user {args.user}') else: room = args.room if args.line: return await send_line_by_line(client, args, room) if args.message: msg = args.message else: msg = sys.stdin.read() await do_with_relogin(client, args, send_message, client, room, msg) await client.close()
async def test_room_id_req(self): """Send a markdown message in a room given as data, and check the result.""" body = "# Hello" messages = [] client = nio.AsyncClient(MATRIX_URL, MATRIX_ID) await client.login(MATRIX_PW) room = await client.room_create() self.assertEqual( bot_req({ "body": body, "room_id": room.room_id }, KEY, room.room_id), { "status": 200, "ret": "OK" }, ) sync = await client.sync() messages = await client.room_messages(room.room_id, sync.next_batch) await client.close() message = messages.chunk[0] self.assertEqual(message.sender, FULL_ID) self.assertEqual(message.body, body) self.assertEqual(message.formatted_body, "<h1>Hello</h1>")
async def test_formatted_body(self): """Send a formatted message, and check the result.""" body = "Formatted message" formatted_body = "<del>markdown</del><strong>Formatted</strong> message" messages = [] client = nio.AsyncClient(MATRIX_URL, MATRIX_ID) await client.login(MATRIX_PW) room = await client.room_create() self.assertEqual( bot_req({ "body": body, "formatted_body": formatted_body }, KEY, room.room_id), { "status": 200, "ret": "OK" }, ) sync = await client.sync() messages = await client.room_messages(room.room_id, sync.next_batch) await client.close() message = messages.chunk[0] self.assertEqual(message.sender, FULL_ID) self.assertEqual(message.body, body) self.assertEqual(message.formatted_body, formatted_body)
async def test_matrix_nio_backend_send_message(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) test_server = "test.matrix.org" test_user = f"@test_user:{test_server}" event_id = "1234567890" room_id = "test_room" backend.client = nio.AsyncClient(test_server, user=test_user, device_id="test_device") backend.client.rooms = { "test_room": "Test Room", "other_test_room": "Test Room" } backend.client.room_send = mock.Mock( return_value=aiounittest.futurized( RoomSendResponse.from_dict({"event_id": event_id}, room_id))) message_text = "Test message" test_message = Message( message_text, matrix_nio.MatrixNioPerson("an_id", client=backend.client, emails=["*****@*****.**"], full_name="")) test_message.to = matrix_nio.MatrixNioRoom("test_room", client=backend.client, title="A title") test_message.to.room = "test_room" result = await backend._send_message(test_message) self.assertIsInstance(result, RoomSendResponse) self.assertEqual(result.room_id, room_id) self.assertEqual(result.event_id, event_id) # TODO: Add assert called once with backend.client.room_send.assert_called_once()
def test_matrix_nio_backend_serve_once_not_logged_in_has_not_synced_error_sync( self): backend = matrix_nio.MatrixNioBackend(self.bot_config) backend.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") backend.client.access_token = True user_id = "@example:localhost" login_response = LoginResponse.from_dict({ "user_id": user_id, "device_id": "device_id", "access_token": "12345", }) login_response_mock = mock.Mock( return_value=aiounittest.futurized(login_response)) backend.client.login_raw = login_response_mock sync_mock = mock.Mock(return_value=aiounittest.futurized( ErrorResponse.from_dict({ "errcode": "ERROR_SYNCING", "error": "Error syncing", "retry_after_ms": 10000 }))) backend.client.sync = sync_mock with self.assertRaises(ValueError): backend.serve_once() sync_mock.assert_called_once_with(full_state=True)
def test_matrix_nio_room_from_matrix_room(self): client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") matrix_room = MatrixRoom("an_id", "an_owner") client.rooms = {matrix_room.room_id: matrix_room} matrix_nio_room = matrix_nio.MatrixNioRoom.from_matrix_room( matrix_room, client) self.assertEqual(matrix_nio_room.matrix_room, matrix_room) self.assertEqual(matrix_nio_room.id, matrix_room.room_id)
async def run(self): self.client = nio.AsyncClient(self.homeserver, self.matrix_id) await self.client.login(self.password) self._started_timestamp = int(datetime.datetime.now().timestamp() * 1000) # matrix-nio type annotations are wrong for asyncclients # noinspection PyTypeChecker self.client.add_event_callback(self.handle_message, (nio.RoomMessageText, )) await self.client.sync_forever()
async def fetch_homeservers(self) -> None: """Retrieve a list of public homeservers and add them to our model.""" @client_session # need to trigger this decorator for creation async def have_session_be_created(*_): pass # We just want that client's aiohttp session, that way we don't have # to depend ourselves on aiohttp + aiohttp-socks proxy = self.settings.General.proxy client = nio.AsyncClient(homeserver="", proxy=proxy) await have_session_be_created(client) session = client.client_session # aiohttp only has "timeout" in 3.7.0+ timeout = getattr(session, "timeout", session._timeout) session = type(session)( raise_for_status = True, timeout = type(timeout)(total=20), connector = session.connector, ) api_list = "https://publiclist.anchel.nl/publiclist.json" response = await session.get(api_list) coros = [] for server in (await response.json()): homeserver_url = server["homeserver"] if homeserver_url.startswith("http://"): # insecure server continue if not re.match(r"^https?://.+", homeserver_url): homeserver_url = f"https://{homeserver_url}" if server["country"] == "USA": server["country"] = "United States" stability, durations = \ self._get_homeserver_stability(server["monitor"]["logs"]) self.models["homeservers"][homeserver_url] = Homeserver( id = homeserver_url, name = server["name"], site_url = server["url"], country = server["country"], stability = stability, downtimes_ms = [d.total_seconds() * 1000 for d in durations], ) coros.append(self._ping_homeserver(session, homeserver_url)) await asyncio.gather(*coros) await session.close()
async def test_gitlab_teams_body(self): """Send a markdown message, and check the result.""" messages = [] client = nio.AsyncClient(MATRIX_URL, MATRIX_ID) await client.login(MATRIX_PW) room = await client.room_create() with open("tests/example_gitlab_teams.json") as f: example_gitlab_teams_request = f.read() self.assertEqual( httpx.post( f"{BOT_URL}/{room.room_id}", params={ "formatter": "gitlab_teams", "key": KEY }, content=example_gitlab_teams_request, ).json(), { "status": 200, "ret": "OK" }, ) sync = await client.sync() messages = await client.room_messages(room.room_id, sync.next_batch) await client.close() message = messages.chunk[0] self.assertEqual(message.sender, FULL_ID) self.assertEqual( message.body, "John Doe pushed to branch [master](https://gitlab.com/jdoe/test/commits" + "/master) in [John Doe / test](https://gitlab.com/jdoe/test) \u2192 [Com" + "pare changes](https://gitlab.com/jdoe/test/compare/b76004b20503d4d506e5" + "1a670de095cc063e4707...3517b06c64c9d349e2213650d6c009db0471361e) \n\n*" + " [3517b06c](https://gitlab.com/jdoe/test/-/commit/3517b06c64c9d349e2213" + "650d6c009db0471361e): Merge branch 'prod' into 'master' - John Doe \n*" + " [1f661795](https://gitlab.com/jdoe/test/-/commit/1f661795b220c5fe352f3" + "91eb8de3ac4fcc6fc1d): Merge branch 'revert-a827b196' into 'prod' - John" + " Doe \n* [b76004b2](https://gitlab.com/jdoe/test/-/commit/b76004b20503" + "d4d506e51a670de095cc063e4707): Merge branch 'revert-a827b196' into 'mas" + "ter' - John Doe", )
def test_matrix_nio_backend_query_empty_room(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) backend.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") room_id1 = "test_room" room_id2 = "another_test_room" backend.client.rooms = { room_id1: MatrixRoom(room_id1, "owner1"), room_id2: MatrixRoom(room_id2, "owner2") } self.assertEqual(backend.query_room("non_existent_room"), None)
def test_matrix_nio_backend_serve_once_logged_in_has_synced(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) backend.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") backend.has_synced = True # Needed for ensuring that backend.client.logged_in = True backend.client.access_token = True sync_forever_mock = mock.Mock(return_value=aiounittest.futurized(True)) backend.client.sync_forever = sync_forever_mock backend.serve_once() sync_forever_mock.assert_called_once_with(30000, full_state=True)
def test_matrix_nio_backend_prefix_groupchat_reply(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) backend.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") full_name = "Charles de Gaulle" person = matrix_nio.MatrixNioPerson("an_id", backend.client, full_name, ["*****@*****.**"]) message = Message("A message") message_body = f"@{person.fullname} {message.body}" backend.prefix_groupchat_reply(message, person) self.assertEqual(message.body, message_body)
async def connect(self): """Create connection object with chat library.""" config = nio.AsyncClientConfig( nio.ClientConfig(encryption_enabled=False, pickle_key="")) mapi = nio.AsyncClient(self.homeserver, self.mxid, config=config) login_response = await mapi.login(password=self.password, device_name=self.device_name) if isinstance(login_response, nio.LoginError): _LOGGER.error( f"Error while connecting: {login_response.message} (status code {login_response.status_code})" ) return mapi.token = login_response.access_token mapi.sync_token = None for roomname, room in self.rooms.items(): response = await mapi.join(room["alias"]) if isinstance(response, nio.JoinError): _LOGGER.error( f"Error while joining room: {room['alias']}, Message: {response.message} (status code {response.status_code})" ) else: self.room_ids[roomname] = response.room_id self.connection = mapi # Create a filter now, saves time on each later sync self.filter_id = await self.make_filter(mapi, self.filter_json) first_filter_id = await self.make_filter( mapi, '{ "room": { "timeline" : { "limit" : 1 } } }') # Do initial sync so we don't get old messages later. response = await self.connection.sync(timeout=3000, sync_filter=first_filter_id) if isinstance(response, nio.SyncError): _LOGGER.error( f"Error during initial sync: {response.message} (status code {response.status_code})" ) return self.connection.sync_token = response.next_batch if self.nick: display_name = await self.connection.get_displayname(self.mxid) if display_name != self.nick: await self.connection.set_displayname(self.nick)
async def test_reconnect(self): """Check the reconnecting path.""" client = nio.AsyncClient(MATRIX_URL, MATRIX_ID) await client.login(MATRIX_PW) room = await client.room_create() await client.logout(all_devices=True) await client.close() self.assertEqual( bot_req({"body": "Re"}, KEY, room.room_id), { "status": 200, "ret": "OK" }, )
async def init_matrix(): cli = nio.AsyncClient( homeserver=config["matrix"]["hs_url"], user=config["matrix"]["mxid"], ) await cli.login(config["matrix"]["password"]) # If the user isn't in the room, join it. room_id = config["matrix"]["room_id"] res = await cli.joined_rooms() if room_id not in res.rooms: await cli.join(room_id) return cli
def test_matrix_nio_backend_is_not_from_self(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) test_user_id = "test_user" backend.client = nio.AsyncClient("test.matrix.org", user=test_user_id, device_id="test_device") message_text = "Test message" response_text = "A response" test_message = Message( message_text, matrix_nio.MatrixNioPerson("another_test_user_id", client=backend.client, emails=["*****@*****.**"], full_name="")) self.assertFalse(backend.is_from_self(test_message))
def __init__(self, config): super().__init__(config) self.has_synced = False self.identity = config.BOT_IDENTITY for key in ('email', 'auth_dict', 'site'): if key not in self.identity: log.fatal( f"You need to supply the key `{key}` for me to use. `{key}` and its value " "can be found in your bot's `matrixniorc` config file.") sys.exit(1) # Store the sync token in order to avoid replay of old messages. config = AsyncClientConfig(store_sync_tokens=True) self.client = nio.AsyncClient(self.identity['site'], self.identity['email'], config=config)
async def test_matrix_nio_backend_build_identifier_error(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) backend.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") backend.client.get_profile = mock.Mock( return_value=aiounittest.futurized( ProfileGetError.from_dict({ "errcode": "ERROR_GETTING_PROFILE", "error": "Error fetching profile", "retry_after_ms": 10000 }))) test_id = "test_id" with self.assertRaises(ValueError): test_identifier = await asyncio.gather( backend.build_identifier(test_id))
def test_matrix_nio_room_destroy(self): matrix_client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") room1 = nio.MatrixRoom("nio_room1", "room1_owner") rooms = {"nio_room1": room1} matrix_client.rooms = rooms nio_room1 = matrix_nio.MatrixNioRoom("nio_room1", client=matrix_client, title="nio_room1 title", subject="nio_room1 subject") matrix_client.room_forget = mock.Mock( return_value=aiounittest.futurized( RoomForgetResponse.from_dict({}, "nio_room1"))) nio_room1.destroy() matrix_client.room_forget.assert_called_once_with("nio_room1")
def test_matrix_nio_backend_query_room(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) backend.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") room_id1 = "test_room" room_id2 = "another_test_room" backend.client.rooms = { room_id1: MatrixRoom(room_id1, "owner1"), room_id2: MatrixRoom(room_id2, "owner2") } result_room1 = backend.query_room(room_id1) result_room2 = backend.query_room(room_id2) self.assertEqual(result_room1.id, room_id1) self.assertEqual(result_room2.id, room_id2)
def test_matrix_nio_backend_rooms(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) backend.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") room_id1 = "test_room" room_id2 = "another_test_room" backend.client.rooms = { room_id1: MatrixRoom(room_id1, "owner1"), room_id2: MatrixRoom(room_id2, "owner2") } result = backend.rooms() result = list(result.keys()) self.assertIn(room_id1, result) self.assertIn(room_id2, result)
def __load_client(self) -> nio.AsyncClient: client = nio.AsyncClient( homeserver=self.__config.get_home_server(), user=self.__config.get_user_id(), device_id=self.__config.get_device_id(), store_path=self.__config.get_store_path(), config=self.__client_config, ssl=True ) client.restore_login( user_id=self.__config.get_user_id(), device_id=self.__config.get_device_id(), access_token=self.__config.get_access_token() ) return client
def __init__(self, method_name): super().__init__(method_name) self.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") self.client.rooms = { "test_room": "empty_room", "other_test_room": "also_empty_room" } self.person_id = "12345" self.full_name = "Charles de Gaulle" self.emails = ["*****@*****.**", "*****@*****.**"] self.person1 = matrix_nio.MatrixNioPerson(self.person_id, client=self.client, full_name=self.full_name, emails=self.emails)
def test_matrix_nio_backend_build_reply(self): backend = matrix_nio.MatrixNioBackend(self.bot_config) backend.client = nio.AsyncClient("test.matrix.org", user="******", device_id="test_device") message_text = "Test message" response_text = "A response" test_message = Message( message_text, matrix_nio.MatrixNioPerson("an_id", client=backend.client, emails=["*****@*****.**"], full_name="")) response = backend.build_reply(test_message, response_text) self.assertIsInstance(response, Message) self.assertEqual(response.to, test_message.frm) self.assertEqual(response.body, f"{message_text}\n{response_text}")