diff options
Diffstat (limited to 'tests/federation/test_federation.py')
-rw-r--r-- | tests/federation/test_federation.py | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/tests/federation/test_federation.py b/tests/federation/test_federation.py new file mode 100644 index 0000000000..1792f9de56 --- /dev/null +++ b/tests/federation/test_federation.py @@ -0,0 +1,240 @@ +# trial imports +from twisted.internet import defer +from twisted.trial import unittest + +# python imports +from mock import Mock +import logging + +from ..utils import MockHttpServer + +from synapse.server import HomeServer +from synapse.federation import initialize_http_replication +from synapse.federation.units import Pdu +from synapse.storage.pdu import PduTuple, PduEntry + + +logging.getLogger().addHandler(logging.NullHandler()) + + +def make_pdu(prev_pdus=[], **kwargs): + """Provide some default fields for making a PduTuple.""" + pdu_fields = { + "is_state": False, + "unrecognized_keys": [], + "outlier": False, + "have_processed": True, + "state_key": None, + "power_level": None, + "prev_state_id": None, + "prev_state_origin": None, + } + pdu_fields.update(kwargs) + + return PduTuple(PduEntry(**pdu_fields), prev_pdus) + + +class MockClock(object): + now = 1000 + + def time(self): + return self.now + + def time_msec(self): + return self.time() * 1000 + + +class FederationTestCase(unittest.TestCase): + def setUp(self): + self.mock_http_server = MockHttpServer() + self.mock_http_client = Mock(spec=[ + "put_json", + ]) + self.mock_persistence = Mock(spec=[ + "get_current_state_for_context", + "get_pdu", + "persist_pdu", + "update_min_depth_for_context", + "prep_send_transaction", + "delivered_txn", + "get_received_txn_response", + "set_received_txn_response", + ]) + self.mock_persistence.get_received_txn_response.return_value = ( + defer.succeed(None) + ) + self.clock = MockClock() + hs = HomeServer("test", + http_server=self.mock_http_server, + http_client=self.mock_http_client, + db_pool=None, + datastore=self.mock_persistence, + clock=self.clock, + ) + self.federation = initialize_http_replication(hs) + self.distributor = hs.get_distributor() + + @defer.inlineCallbacks + def test_get_state(self): + self.mock_persistence.get_current_state_for_context.return_value = ( + defer.succeed([]) + ) + + # Empty context initially + (code, response) = yield self.mock_http_server.trigger("GET", + "/state/my-context/", None) + self.assertEquals(200, code) + self.assertFalse(response["pdus"]) + + # Now lets give the context some state + self.mock_persistence.get_current_state_for_context.return_value = ( + defer.succeed([ + make_pdu( + pdu_id="the-pdu-id", + origin="red", + context="my-context", + pdu_type="m.topic", + ts=123456789000, + depth=1, + is_state=True, + content_json='{"topic":"The topic"}', + state_key="", + power_level=1000, + prev_state_id="last-pdu-id", + prev_state_origin="blue", + ), + ]) + ) + + (code, response) = yield self.mock_http_server.trigger("GET", + "/state/my-context/", None) + self.assertEquals(200, code) + self.assertEquals(1, len(response["pdus"])) + + @defer.inlineCallbacks + def test_get_pdu(self): + self.mock_persistence.get_pdu.return_value = ( + defer.succeed(None) + ) + + (code, response) = yield self.mock_http_server.trigger("GET", + "/pdu/red/abc123def456/", None) + self.assertEquals(404, code) + + # Now insert such a PDU + self.mock_persistence.get_pdu.return_value = ( + defer.succeed( + make_pdu( + pdu_id="abc123def456", + origin="red", + context="my-context", + pdu_type="m.text", + ts=123456789001, + depth=1, + content_json='{"text":"Here is the message"}', + ) + ) + ) + + (code, response) = yield self.mock_http_server.trigger("GET", + "/pdu/red/abc123def456/", None) + self.assertEquals(200, code) + self.assertEquals(1, len(response["pdus"])) + self.assertEquals("m.text", response["pdus"][0]["pdu_type"]) + + @defer.inlineCallbacks + def test_send_pdu(self): + self.mock_http_client.put_json.return_value = defer.succeed( + (200, "OK") + ) + + pdu = Pdu( + pdu_id="abc123def456", + origin="red", + destinations=["remote"], + context="my-context", + ts=123456789002, + pdu_type="m.test", + content={"testing": "content here"}, + depth=1, + ) + + yield self.federation.send_pdu(pdu) + + self.mock_http_client.put_json.assert_called_with( + "remote", + path="/send/1000000/", + data={ + "ts": 1000000, + "origin": "test", + "pdus": [ + { + "origin": "red", + "pdu_id": "abc123def456", + "prev_pdus": [], + "ts": 123456789002, + "context": "my-context", + "pdu_type": "m.test", + "is_state": False, + "content": {"testing": "content here"}, + "depth": 1, + }, + ] + } + ) + + @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="/send/1000000/", + data={ + "origin": "test", + "ts": 1000000, + "pdus": [], + "edus": [ + { + "origin": "test", + "destination": "remote", + "edu_type": "m.test", + "content": {"testing": "content here"}, + } + ], + }) + + @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_http_server.trigger("PUT", "/send/1001000/", + """{ + "origin": "remote", + "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"} + ) |