test_federation.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. # Copyright 2014 OpenMarket Ltd
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. # trial imports
  15. from twisted.internet import defer
  16. from tests import unittest
  17. # python imports
  18. from mock import Mock, ANY
  19. from ..utils import MockHttpResource, MockClock, setup_test_homeserver
  20. from synapse.federation import initialize_http_replication
  21. from synapse.events import FrozenEvent
  22. from synapse.storage.transactions import DestinationsTable
  23. def make_pdu(prev_pdus=[], **kwargs):
  24. """Provide some default fields for making a PduTuple."""
  25. pdu_fields = {
  26. "state_key": None,
  27. "prev_events": prev_pdus,
  28. }
  29. pdu_fields.update(kwargs)
  30. return FrozenEvent(pdu_fields)
  31. class FederationTestCase(unittest.TestCase):
  32. @defer.inlineCallbacks
  33. def setUp(self):
  34. self.mock_resource = MockHttpResource()
  35. self.mock_http_client = Mock(spec=[
  36. "get_json",
  37. "put_json",
  38. ])
  39. self.mock_persistence = Mock(spec=[
  40. "prep_send_transaction",
  41. "delivered_txn",
  42. "get_received_txn_response",
  43. "set_received_txn_response",
  44. "get_destination_retry_timings",
  45. "get_auth_chain",
  46. ])
  47. self.mock_persistence.get_received_txn_response.return_value = (
  48. defer.succeed(None)
  49. )
  50. self.mock_persistence.get_destination_retry_timings.return_value = (
  51. defer.succeed(DestinationsTable.EntryType("", 0, 0))
  52. )
  53. self.mock_persistence.get_auth_chain.return_value = []
  54. self.clock = MockClock()
  55. hs = yield setup_test_homeserver(
  56. resource_for_federation=self.mock_resource,
  57. http_client=self.mock_http_client,
  58. datastore=self.mock_persistence,
  59. clock=self.clock,
  60. keyring=Mock(),
  61. )
  62. self.federation = initialize_http_replication(hs)
  63. self.distributor = hs.get_distributor()
  64. @defer.inlineCallbacks
  65. def test_get_state(self):
  66. mock_handler = Mock(spec=[
  67. "get_state_for_pdu",
  68. ])
  69. self.federation.set_handler(mock_handler)
  70. mock_handler.get_state_for_pdu.return_value = defer.succeed([])
  71. # Empty context initially
  72. (code, response) = yield self.mock_resource.trigger(
  73. "GET",
  74. "/_matrix/federation/v1/state/my-context/",
  75. None
  76. )
  77. self.assertEquals(200, code)
  78. self.assertFalse(response["pdus"])
  79. # Now lets give the context some state
  80. mock_handler.get_state_for_pdu.return_value = (
  81. defer.succeed([
  82. make_pdu(
  83. event_id="the-pdu-id",
  84. origin="red",
  85. user_id="@a:red",
  86. room_id="my-context",
  87. type="m.topic",
  88. origin_server_ts=123456789000,
  89. depth=1,
  90. content={"topic": "The topic"},
  91. state_key="",
  92. power_level=1000,
  93. prev_state="last-pdu-id",
  94. ),
  95. ])
  96. )
  97. (code, response) = yield self.mock_resource.trigger(
  98. "GET",
  99. "/_matrix/federation/v1/state/my-context/",
  100. None
  101. )
  102. self.assertEquals(200, code)
  103. self.assertEquals(1, len(response["pdus"]))
  104. @defer.inlineCallbacks
  105. def test_get_pdu(self):
  106. mock_handler = Mock(spec=[
  107. "get_persisted_pdu",
  108. ])
  109. self.federation.set_handler(mock_handler)
  110. mock_handler.get_persisted_pdu.return_value = (
  111. defer.succeed(None)
  112. )
  113. (code, response) = yield self.mock_resource.trigger(
  114. "GET",
  115. "/_matrix/federation/v1/event/abc123def456/",
  116. None
  117. )
  118. self.assertEquals(404, code)
  119. # Now insert such a PDU
  120. mock_handler.get_persisted_pdu.return_value = (
  121. defer.succeed(
  122. make_pdu(
  123. event_id="abc123def456",
  124. origin="red",
  125. user_id="@a:red",
  126. room_id="my-context",
  127. type="m.text",
  128. origin_server_ts=123456789001,
  129. depth=1,
  130. content={"text": "Here is the message"},
  131. )
  132. )
  133. )
  134. (code, response) = yield self.mock_resource.trigger(
  135. "GET",
  136. "/_matrix/federation/v1/event/abc123def456/",
  137. None
  138. )
  139. self.assertEquals(200, code)
  140. self.assertEquals(1, len(response["pdus"]))
  141. self.assertEquals("m.text", response["pdus"][0]["type"])
  142. @defer.inlineCallbacks
  143. def test_send_pdu(self):
  144. self.mock_http_client.put_json.return_value = defer.succeed(
  145. (200, "OK")
  146. )
  147. pdu = make_pdu(
  148. event_id="abc123def456",
  149. origin="red",
  150. user_id="@a:red",
  151. room_id="my-context",
  152. type="m.text",
  153. origin_server_ts=123456789001,
  154. depth=1,
  155. content={"text": "Here is the message"},
  156. )
  157. yield self.federation.send_pdu(pdu, ["remote"])
  158. self.mock_http_client.put_json.assert_called_with(
  159. "remote",
  160. path="/_matrix/federation/v1/send/1000000/",
  161. data={
  162. "origin_server_ts": 1000000,
  163. "origin": "test",
  164. "pdus": [
  165. pdu.get_pdu_json(),
  166. ],
  167. 'pdu_failures': [],
  168. },
  169. json_data_callback=ANY,
  170. )
  171. @defer.inlineCallbacks
  172. def test_send_edu(self):
  173. self.mock_http_client.put_json.return_value = defer.succeed(
  174. (200, "OK")
  175. )
  176. yield self.federation.send_edu(
  177. destination="remote",
  178. edu_type="m.test",
  179. content={"testing": "content here"},
  180. )
  181. # MockClock ensures we can guess these timestamps
  182. self.mock_http_client.put_json.assert_called_with(
  183. "remote",
  184. path="/_matrix/federation/v1/send/1000000/",
  185. data={
  186. "origin": "test",
  187. "origin_server_ts": 1000000,
  188. "pdus": [],
  189. "edus": [
  190. {
  191. "edu_type": "m.test",
  192. "content": {"testing": "content here"},
  193. }
  194. ],
  195. 'pdu_failures': [],
  196. },
  197. json_data_callback=ANY,
  198. )
  199. @defer.inlineCallbacks
  200. def test_recv_edu(self):
  201. recv_observer = Mock()
  202. recv_observer.return_value = defer.succeed(())
  203. self.federation.register_edu_handler("m.test", recv_observer)
  204. yield self.mock_resource.trigger(
  205. "PUT",
  206. "/_matrix/federation/v1/send/1001000/",
  207. """{
  208. "origin": "remote",
  209. "origin_server_ts": 1001000,
  210. "pdus": [],
  211. "edus": [
  212. {
  213. "origin": "remote",
  214. "destination": "test",
  215. "edu_type": "m.test",
  216. "content": {"testing": "reply here"}
  217. }
  218. ]
  219. }"""
  220. )
  221. recv_observer.assert_called_with(
  222. "remote", {"testing": "reply here"}
  223. )
  224. @defer.inlineCallbacks
  225. def test_send_query(self):
  226. self.mock_http_client.get_json.return_value = defer.succeed(
  227. {"your": "response"}
  228. )
  229. response = yield self.federation.make_query(
  230. destination="remote",
  231. query_type="a-question",
  232. args={"one": "1", "two": "2"},
  233. )
  234. self.assertEquals({"your": "response"}, response)
  235. self.mock_http_client.get_json.assert_called_with(
  236. destination="remote",
  237. path="/_matrix/federation/v1/query/a-question",
  238. args={"one": "1", "two": "2"},
  239. retry_on_dns_fail=True,
  240. )
  241. @defer.inlineCallbacks
  242. def test_recv_query(self):
  243. recv_handler = Mock()
  244. recv_handler.return_value = defer.succeed({"another": "response"})
  245. self.federation.register_query_handler("a-question", recv_handler)
  246. code, response = yield self.mock_resource.trigger(
  247. "GET",
  248. "/_matrix/federation/v1/query/a-question?three=3&four=4",
  249. None
  250. )
  251. self.assertEquals(200, code)
  252. self.assertEquals({"another": "response"}, response)
  253. recv_handler.assert_called_with(
  254. {"three": "3", "four": "4"}
  255. )