diff options
Diffstat (limited to 'tests/federation/test_federation.py')
-rw-r--r-- | tests/federation/test_federation.py | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/tests/federation/test_federation.py b/tests/federation/test_federation.py new file mode 100644 index 00000000..a4ef60b9 --- /dev/null +++ b/tests/federation/test_federation.py @@ -0,0 +1,301 @@ +# Copyright 2014 OpenMarket Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# trial imports +from twisted.internet import defer +from tests import unittest + +# python imports +from mock import Mock, ANY + +from ..utils import MockHttpResource, MockClock, setup_test_homeserver + +from synapse.federation import initialize_http_replication +from synapse.events import FrozenEvent + + +def make_pdu(prev_pdus=[], **kwargs): + """Provide some default fields for making a PduTuple.""" + pdu_fields = { + "state_key": None, + "prev_events": prev_pdus, + } + pdu_fields.update(kwargs) + + return FrozenEvent(pdu_fields) + + +class FederationTestCase(unittest.TestCase): + @defer.inlineCallbacks + def setUp(self): + self.mock_resource = MockHttpResource() + self.mock_http_client = Mock(spec=[ + "get_json", + "put_json", + ]) + self.mock_persistence = Mock(spec=[ + "prep_send_transaction", + "delivered_txn", + "get_received_txn_response", + "set_received_txn_response", + "get_destination_retry_timings", + "get_auth_chain", + ]) + self.mock_persistence.get_received_txn_response.return_value = ( + defer.succeed(None) + ) + + retry_timings_res = { + "destination": "", + "retry_last_ts": 0, + "retry_interval": 0, + } + self.mock_persistence.get_destination_retry_timings.return_value = ( + defer.succeed(retry_timings_res) + ) + self.mock_persistence.get_auth_chain.return_value = [] + self.clock = MockClock() + hs = yield setup_test_homeserver( + resource_for_federation=self.mock_resource, + http_client=self.mock_http_client, + datastore=self.mock_persistence, + clock=self.clock, + keyring=Mock(), + ) + self.federation = initialize_http_replication(hs) + self.distributor = hs.get_distributor() + + @defer.inlineCallbacks + def test_get_state(self): + mock_handler = Mock(spec=[ + "get_state_for_pdu", + ]) + + self.federation.set_handler(mock_handler) + + mock_handler.get_state_for_pdu.return_value = defer.succeed([]) + + # Empty context initially + (code, response) = yield self.mock_resource.trigger( + "GET", + "/_matrix/federation/v1/state/my-context/", + None + ) + self.assertEquals(200, code) + self.assertFalse(response["pdus"]) + + # Now lets give the context some state + mock_handler.get_state_for_pdu.return_value = ( + defer.succeed([ + make_pdu( + event_id="the-pdu-id", + origin="red", + user_id="@a:red", + room_id="my-context", + type="m.topic", + origin_server_ts=123456789000, + depth=1, + content={"topic": "The topic"}, + state_key="", + power_level=1000, + prev_state="last-pdu-id", + ), + ]) + ) + + (code, response) = yield self.mock_resource.trigger( + "GET", + "/_matrix/federation/v1/state/my-context/", + None + ) + self.assertEquals(200, code) + self.assertEquals(1, len(response["pdus"])) + + @defer.inlineCallbacks + def test_get_pdu(self): + mock_handler = Mock(spec=[ + "get_persisted_pdu", + ]) + + self.federation.set_handler(mock_handler) + + mock_handler.get_persisted_pdu.return_value = ( + defer.succeed(None) + ) + + (code, response) = yield self.mock_resource.trigger( + "GET", + "/_matrix/federation/v1/event/abc123def456/", + None + ) + self.assertEquals(404, code) + + # Now insert such a PDU + mock_handler.get_persisted_pdu.return_value = ( + defer.succeed( + make_pdu( + event_id="abc123def456", + origin="red", + user_id="@a:red", + room_id="my-context", + type="m.text", + origin_server_ts=123456789001, + depth=1, + content={"text": "Here is the message"}, + ) + ) + ) + + (code, response) = yield self.mock_resource.trigger( + "GET", + "/_matrix/federation/v1/event/abc123def456/", + None + ) + self.assertEquals(200, code) + self.assertEquals(1, len(response["pdus"])) + self.assertEquals("m.text", response["pdus"][0]["type"]) + + @defer.inlineCallbacks + def test_send_pdu(self): + self.mock_http_client.put_json.return_value = defer.succeed( + (200, "OK") + ) + + pdu = make_pdu( + event_id="abc123def456", + origin="red", + user_id="@a:red", + room_id="my-context", + type="m.text", + origin_server_ts=123456789001, + depth=1, + content={"text": "Here is the message"}, + ) + + yield self.federation.send_pdu(pdu, ["remote"]) + + self.mock_http_client.put_json.assert_called_with( + "remote", + path="/_matrix/federation/v1/send/1000000/", + data={ + "origin_server_ts": 1000000, + "origin": "test", + "pdus": [ + pdu.get_pdu_json(), + ], + 'pdu_failures': [], + }, + json_data_callback=ANY, + ) + + @defer.inlineCallbacks + def test_send_edu(self): + self.mock_http_client.put_json.return_value = defer.succeed( + (200, "OK") + ) + + yield self.federation.send_edu( + destination="remote", + edu_type="m.test", + content={"testing": "content here"}, + ) + + # MockClock ensures we can guess these timestamps + self.mock_http_client.put_json.assert_called_with( + "remote", + path="/_matrix/federation/v1/send/1000000/", + data={ + "origin": "test", + "origin_server_ts": 1000000, + "pdus": [], + "edus": [ + { + "edu_type": "m.test", + "content": {"testing": "content here"}, + } + ], + 'pdu_failures': [], + }, + json_data_callback=ANY, + ) + + @defer.inlineCallbacks + def test_recv_edu(self): + recv_observer = Mock() + recv_observer.return_value = defer.succeed(()) + + self.federation.register_edu_handler("m.test", recv_observer) + + yield self.mock_resource.trigger( + "PUT", + "/_matrix/federation/v1/send/1001000/", + """{ + "origin": "remote", + "origin_server_ts": 1001000, + "pdus": [], + "edus": [ + { + "origin": "remote", + "destination": "test", + "edu_type": "m.test", + "content": {"testing": "reply here"} + } + ] + }""" + ) + + recv_observer.assert_called_with( + "remote", {"testing": "reply here"} + ) + + @defer.inlineCallbacks + def test_send_query(self): + self.mock_http_client.get_json.return_value = defer.succeed( + {"your": "response"} + ) + + response = yield self.federation.make_query( + destination="remote", + query_type="a-question", + args={"one": "1", "two": "2"}, + ) + + self.assertEquals({"your": "response"}, response) + + self.mock_http_client.get_json.assert_called_with( + destination="remote", + path="/_matrix/federation/v1/query/a-question", + args={"one": "1", "two": "2"}, + retry_on_dns_fail=True, + ) + + @defer.inlineCallbacks + def test_recv_query(self): + recv_handler = Mock() + recv_handler.return_value = defer.succeed({"another": "response"}) + + self.federation.register_query_handler("a-question", recv_handler) + + code, response = yield self.mock_resource.trigger( + "GET", + "/_matrix/federation/v1/query/a-question?three=3&four=4", + None + ) + + self.assertEquals(200, code) + self.assertEquals({"another": "response"}, response) + + recv_handler.assert_called_with( + {"three": "3", "four": "4"} + ) |