test_federation.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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. def make_pdu(prev_pdus=[], **kwargs):
  23. """Provide some default fields for making a PduTuple."""
  24. pdu_fields = {
  25. "state_key": None,
  26. "prev_events": prev_pdus,
  27. }
  28. pdu_fields.update(kwargs)
  29. return FrozenEvent(pdu_fields)
  30. class FederationTestCase(unittest.TestCase):
  31. @defer.inlineCallbacks
  32. def setUp(self):
  33. self.mock_resource = MockHttpResource()
  34. self.mock_http_client = Mock(spec=[
  35. "get_json",
  36. "put_json",
  37. ])
  38. self.mock_persistence = Mock(spec=[
  39. "prep_send_transaction",
  40. "delivered_txn",
  41. "get_received_txn_response",
  42. "set_received_txn_response",
  43. "get_destination_retry_timings",
  44. "get_auth_chain",
  45. ])
  46. self.mock_persistence.get_received_txn_response.return_value = (
  47. defer.succeed(None)
  48. )
  49. retry_timings_res = {
  50. "destination": "",
  51. "retry_last_ts": 0,
  52. "retry_interval": 0,
  53. }
  54. self.mock_persistence.get_destination_retry_timings.return_value = (
  55. defer.succeed(retry_timings_res)
  56. )
  57. self.mock_persistence.get_auth_chain.return_value = []
  58. self.clock = MockClock()
  59. hs = yield setup_test_homeserver(
  60. resource_for_federation=self.mock_resource,
  61. http_client=self.mock_http_client,
  62. datastore=self.mock_persistence,
  63. clock=self.clock,
  64. keyring=Mock(),
  65. )
  66. self.federation = initialize_http_replication(hs)
  67. self.distributor = hs.get_distributor()
  68. @defer.inlineCallbacks
  69. def test_get_state(self):
  70. mock_handler = Mock(spec=[
  71. "get_state_for_pdu",
  72. ])
  73. self.federation.set_handler(mock_handler)
  74. mock_handler.get_state_for_pdu.return_value = defer.succeed([])
  75. # Empty context initially
  76. (code, response) = yield self.mock_resource.trigger(
  77. "GET",
  78. "/_matrix/federation/v1/state/my-context/",
  79. None
  80. )
  81. self.assertEquals(200, code)
  82. self.assertFalse(response["pdus"])
  83. # Now lets give the context some state
  84. mock_handler.get_state_for_pdu.return_value = (
  85. defer.succeed([
  86. make_pdu(
  87. event_id="the-pdu-id",
  88. origin="red",
  89. user_id="@a:red",
  90. room_id="my-context",
  91. type="m.topic",
  92. origin_server_ts=123456789000,
  93. depth=1,
  94. content={"topic": "The topic"},
  95. state_key="",
  96. power_level=1000,
  97. prev_state="last-pdu-id",
  98. ),
  99. ])
  100. )
  101. (code, response) = yield self.mock_resource.trigger(
  102. "GET",
  103. "/_matrix/federation/v1/state/my-context/",
  104. None
  105. )
  106. self.assertEquals(200, code)
  107. self.assertEquals(1, len(response["pdus"]))
  108. @defer.inlineCallbacks
  109. def test_get_pdu(self):
  110. mock_handler = Mock(spec=[
  111. "get_persisted_pdu",
  112. ])
  113. self.federation.set_handler(mock_handler)
  114. mock_handler.get_persisted_pdu.return_value = (
  115. defer.succeed(None)
  116. )
  117. (code, response) = yield self.mock_resource.trigger(
  118. "GET",
  119. "/_matrix/federation/v1/event/abc123def456/",
  120. None
  121. )
  122. self.assertEquals(404, code)
  123. # Now insert such a PDU
  124. mock_handler.get_persisted_pdu.return_value = (
  125. defer.succeed(
  126. make_pdu(
  127. event_id="abc123def456",
  128. origin="red",
  129. user_id="@a:red",
  130. room_id="my-context",
  131. type="m.text",
  132. origin_server_ts=123456789001,
  133. depth=1,
  134. content={"text": "Here is the message"},
  135. )
  136. )
  137. )
  138. (code, response) = yield self.mock_resource.trigger(
  139. "GET",
  140. "/_matrix/federation/v1/event/abc123def456/",
  141. None
  142. )
  143. self.assertEquals(200, code)
  144. self.assertEquals(1, len(response["pdus"]))
  145. self.assertEquals("m.text", response["pdus"][0]["type"])
  146. @defer.inlineCallbacks
  147. def test_send_pdu(self):
  148. self.mock_http_client.put_json.return_value = defer.succeed(
  149. (200, "OK")
  150. )
  151. pdu = make_pdu(
  152. event_id="abc123def456",
  153. origin="red",
  154. user_id="@a:red",
  155. room_id="my-context",
  156. type="m.text",
  157. origin_server_ts=123456789001,
  158. depth=1,
  159. content={"text": "Here is the message"},
  160. )
  161. yield self.federation.send_pdu(pdu, ["remote"])
  162. self.mock_http_client.put_json.assert_called_with(
  163. "remote",
  164. path="/_matrix/federation/v1/send/1000000/",
  165. data={
  166. "origin_server_ts": 1000000,
  167. "origin": "test",
  168. "pdus": [
  169. pdu.get_pdu_json(),
  170. ],
  171. 'pdu_failures': [],
  172. },
  173. json_data_callback=ANY,
  174. )
  175. @defer.inlineCallbacks
  176. def test_send_edu(self):
  177. self.mock_http_client.put_json.return_value = defer.succeed(
  178. (200, "OK")
  179. )
  180. yield self.federation.send_edu(
  181. destination="remote",
  182. edu_type="m.test",
  183. content={"testing": "content here"},
  184. )
  185. # MockClock ensures we can guess these timestamps
  186. self.mock_http_client.put_json.assert_called_with(
  187. "remote",
  188. path="/_matrix/federation/v1/send/1000000/",
  189. data={
  190. "origin": "test",
  191. "origin_server_ts": 1000000,
  192. "pdus": [],
  193. "edus": [
  194. {
  195. "edu_type": "m.test",
  196. "content": {"testing": "content here"},
  197. }
  198. ],
  199. 'pdu_failures': [],
  200. },
  201. json_data_callback=ANY,
  202. )
  203. @defer.inlineCallbacks
  204. def test_recv_edu(self):
  205. recv_observer = Mock()
  206. recv_observer.return_value = defer.succeed(())
  207. self.federation.register_edu_handler("m.test", recv_observer)
  208. yield self.mock_resource.trigger(
  209. "PUT",
  210. "/_matrix/federation/v1/send/1001000/",
  211. """{
  212. "origin": "remote",
  213. "origin_server_ts": 1001000,
  214. "pdus": [],
  215. "edus": [
  216. {
  217. "origin": "remote",
  218. "destination": "test",
  219. "edu_type": "m.test",
  220. "content": {"testing": "reply here"}
  221. }
  222. ]
  223. }"""
  224. )
  225. recv_observer.assert_called_with(
  226. "remote", {"testing": "reply here"}
  227. )
  228. @defer.inlineCallbacks
  229. def test_send_query(self):
  230. self.mock_http_client.get_json.return_value = defer.succeed(
  231. {"your": "response"}
  232. )
  233. response = yield self.federation.make_query(
  234. destination="remote",
  235. query_type="a-question",
  236. args={"one": "1", "two": "2"},
  237. )
  238. self.assertEquals({"your": "response"}, response)
  239. self.mock_http_client.get_json.assert_called_with(
  240. destination="remote",
  241. path="/_matrix/federation/v1/query/a-question",
  242. args={"one": "1", "two": "2"},
  243. retry_on_dns_fail=True,
  244. )
  245. @defer.inlineCallbacks
  246. def test_recv_query(self):
  247. recv_handler = Mock()
  248. recv_handler.return_value = defer.succeed({"another": "response"})
  249. self.federation.register_query_handler("a-question", recv_handler)
  250. code, response = yield self.mock_resource.trigger(
  251. "GET",
  252. "/_matrix/federation/v1/query/a-question?three=3&four=4",
  253. None
  254. )
  255. self.assertEquals(200, code)
  256. self.assertEquals({"another": "response"}, response)
  257. recv_handler.assert_called_with(
  258. {"three": "3", "four": "4"}
  259. )