test_fedclient.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2018 New Vector Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from mock import Mock
  16. from twisted.internet.defer import TimeoutError
  17. from twisted.internet.error import ConnectingCancelledError, DNSLookupError
  18. from twisted.web.client import ResponseNeverReceived
  19. from twisted.web.http import HTTPChannel
  20. from synapse.http.matrixfederationclient import (
  21. MatrixFederationHttpClient,
  22. MatrixFederationRequest,
  23. )
  24. from tests.server import FakeTransport
  25. from tests.unittest import HomeserverTestCase
  26. class FederationClientTests(HomeserverTestCase):
  27. def make_homeserver(self, reactor, clock):
  28. hs = self.setup_test_homeserver(reactor=reactor, clock=clock)
  29. hs.tls_client_options_factory = None
  30. return hs
  31. def prepare(self, reactor, clock, homeserver):
  32. self.cl = MatrixFederationHttpClient(self.hs)
  33. self.reactor.lookups["testserv"] = "1.2.3.4"
  34. def test_dns_error(self):
  35. """
  36. If the DNS raising returns an error, it will bubble up.
  37. """
  38. d = self.cl.get_json("testserv2:8008", "foo/bar", timeout=10000)
  39. self.pump()
  40. f = self.failureResultOf(d)
  41. self.assertIsInstance(f.value, DNSLookupError)
  42. def test_client_never_connect(self):
  43. """
  44. If the HTTP request is not connected and is timed out, it'll give a
  45. ConnectingCancelledError or TimeoutError.
  46. """
  47. d = self.cl.get_json("testserv:8008", "foo/bar", timeout=10000)
  48. self.pump()
  49. # Nothing happened yet
  50. self.assertFalse(d.called)
  51. # Make sure treq is trying to connect
  52. clients = self.reactor.tcpClients
  53. self.assertEqual(len(clients), 1)
  54. self.assertEqual(clients[0][0], '1.2.3.4')
  55. self.assertEqual(clients[0][1], 8008)
  56. # Deferred is still without a result
  57. self.assertFalse(d.called)
  58. # Push by enough to time it out
  59. self.reactor.advance(10.5)
  60. f = self.failureResultOf(d)
  61. self.assertIsInstance(f.value, (ConnectingCancelledError, TimeoutError))
  62. def test_client_connect_no_response(self):
  63. """
  64. If the HTTP request is connected, but gets no response before being
  65. timed out, it'll give a ResponseNeverReceived.
  66. """
  67. d = self.cl.get_json("testserv:8008", "foo/bar", timeout=10000)
  68. self.pump()
  69. # Nothing happened yet
  70. self.assertFalse(d.called)
  71. # Make sure treq is trying to connect
  72. clients = self.reactor.tcpClients
  73. self.assertEqual(len(clients), 1)
  74. self.assertEqual(clients[0][0], '1.2.3.4')
  75. self.assertEqual(clients[0][1], 8008)
  76. conn = Mock()
  77. client = clients[0][2].buildProtocol(None)
  78. client.makeConnection(conn)
  79. # Deferred is still without a result
  80. self.assertFalse(d.called)
  81. # Push by enough to time it out
  82. self.reactor.advance(10.5)
  83. f = self.failureResultOf(d)
  84. self.assertIsInstance(f.value, ResponseNeverReceived)
  85. def test_client_gets_headers(self):
  86. """
  87. Once the client gets the headers, _request returns successfully.
  88. """
  89. request = MatrixFederationRequest(
  90. method="GET",
  91. destination="testserv:8008",
  92. path="foo/bar",
  93. )
  94. d = self.cl._send_request(request, timeout=10000)
  95. self.pump()
  96. conn = Mock()
  97. clients = self.reactor.tcpClients
  98. client = clients[0][2].buildProtocol(None)
  99. client.makeConnection(conn)
  100. # Deferred does not have a result
  101. self.assertFalse(d.called)
  102. # Send it the HTTP response
  103. client.dataReceived(b"HTTP/1.1 200 OK\r\nServer: Fake\r\n\r\n")
  104. # We should get a successful response
  105. r = self.successResultOf(d)
  106. self.assertEqual(r.code, 200)
  107. def test_client_headers_no_body(self):
  108. """
  109. If the HTTP request is connected, but gets no response before being
  110. timed out, it'll give a ResponseNeverReceived.
  111. """
  112. d = self.cl.post_json("testserv:8008", "foo/bar", timeout=10000)
  113. self.pump()
  114. conn = Mock()
  115. clients = self.reactor.tcpClients
  116. client = clients[0][2].buildProtocol(None)
  117. client.makeConnection(conn)
  118. # Deferred does not have a result
  119. self.assertFalse(d.called)
  120. # Send it the HTTP response
  121. client.dataReceived(
  122. (b"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n"
  123. b"Server: Fake\r\n\r\n")
  124. )
  125. # Push by enough to time it out
  126. self.reactor.advance(10.5)
  127. f = self.failureResultOf(d)
  128. self.assertIsInstance(f.value, TimeoutError)
  129. def test_client_sends_body(self):
  130. self.cl.post_json(
  131. "testserv:8008", "foo/bar", timeout=10000,
  132. data={"a": "b"}
  133. )
  134. self.pump()
  135. clients = self.reactor.tcpClients
  136. self.assertEqual(len(clients), 1)
  137. client = clients[0][2].buildProtocol(None)
  138. server = HTTPChannel()
  139. client.makeConnection(FakeTransport(server, self.reactor))
  140. server.makeConnection(FakeTransport(client, self.reactor))
  141. self.pump(0.1)
  142. self.assertEqual(len(server.requests), 1)
  143. request = server.requests[0]
  144. content = request.content.read()
  145. self.assertEqual(content, b'{"a":"b"}')