client.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #!/usr/bin/env python
  2. #
  3. # Copyright 2018 Espressif Systems (Shanghai) PTE LTD
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. from __future__ import print_function
  17. from __future__ import unicode_literals
  18. from builtins import str
  19. import http.client
  20. import argparse
  21. try:
  22. import Utility
  23. except ImportError:
  24. import sys
  25. import os
  26. # This environment variable is expected on the host machine
  27. # > export TEST_FW_PATH=~/esp/esp-idf/tools/tiny-test-fw
  28. test_fw_path = os.getenv("TEST_FW_PATH")
  29. if test_fw_path and test_fw_path not in sys.path:
  30. sys.path.insert(0, test_fw_path)
  31. import Utility
  32. def verbose_print(verbosity, *args):
  33. if (verbosity):
  34. Utility.console_log(''.join(str(elems) for elems in args))
  35. def test_val(text, expected, received):
  36. if expected != received:
  37. Utility.console_log(" Fail!")
  38. Utility.console_log(" [reason] " + text + ":")
  39. Utility.console_log(" expected: " + str(expected))
  40. Utility.console_log(" received: " + str(received))
  41. return False
  42. return True
  43. def test_get_handler(ip, port, verbosity=False):
  44. verbose_print(verbosity, "======== GET HANDLER TEST =============")
  45. # Establish HTTP connection
  46. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  47. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  48. uri = "/hello?query1=value1&query2=value2&query3=value3"
  49. # GET hello response
  50. test_headers = {"Test-Header-1":"Test-Value-1", "Test-Header-2":"Test-Value-2"}
  51. verbose_print(verbosity, "Sending GET to URI : ", uri)
  52. verbose_print(verbosity, "Sending additional headers : ")
  53. for k, v in test_headers.items():
  54. verbose_print(verbosity, "\t", k, ": ", v)
  55. sess.request("GET", url=uri, headers=test_headers)
  56. resp = sess.getresponse()
  57. resp_hdrs = resp.getheaders()
  58. resp_data = resp.read().decode()
  59. # Close HTTP connection
  60. sess.close()
  61. if not (
  62. test_val("Status code mismatch", 200, resp.status) and
  63. test_val("Response mismatch", "Custom-Value-1", resp.getheader("Custom-Header-1")) and
  64. test_val("Response mismatch", "Custom-Value-2", resp.getheader("Custom-Header-2")) and
  65. test_val("Response mismatch", "Hello World!", resp_data)
  66. ):
  67. return False
  68. verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
  69. verbose_print(verbosity, "Server response to GET /hello")
  70. verbose_print(verbosity, "Response Headers : ")
  71. for k, v in resp_hdrs:
  72. verbose_print(verbosity, "\t", k, ": ", v)
  73. verbose_print(verbosity, "Response Data : " + resp_data)
  74. verbose_print(verbosity, "========================================\n")
  75. return True
  76. def test_post_handler(ip, port, msg, verbosity=False):
  77. verbose_print(verbosity, "======== POST HANDLER TEST ============")
  78. # Establish HTTP connection
  79. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  80. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  81. # POST message to /echo and get back response
  82. sess.request("POST", url="/echo", body=msg)
  83. resp = sess.getresponse()
  84. resp_data = resp.read().decode()
  85. verbose_print(verbosity, "Server response to POST /echo (" + msg + ")")
  86. verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
  87. verbose_print(verbosity, resp_data)
  88. verbose_print(verbosity, "========================================\n")
  89. # Close HTTP connection
  90. sess.close()
  91. return test_val("Response mismatch", msg, resp_data)
  92. def test_put_handler(ip, port, verbosity=False):
  93. verbose_print(verbosity, "======== PUT HANDLER TEST =============")
  94. # Establish HTTP connection
  95. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  96. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  97. # PUT message to /ctrl to disable /hello and /echo URI handlers
  98. # and set 404 error handler to custom http_404_error_handler()
  99. verbose_print(verbosity, "Disabling /hello and /echo handlers")
  100. sess.request("PUT", url="/ctrl", body="0")
  101. resp = sess.getresponse()
  102. resp.read()
  103. try:
  104. # Send HTTP request to /hello URI
  105. sess.request("GET", url="/hello")
  106. resp = sess.getresponse()
  107. resp_data = resp.read().decode()
  108. # 404 Error must be returned from server as URI /hello is no longer available.
  109. # But the custom error handler http_404_error_handler() will not close the
  110. # session if the requested URI is /hello
  111. if not test_val("Status code mismatch", 404, resp.status):
  112. raise AssertionError
  113. # Compare error response string with expectation
  114. verbose_print(verbosity, "Response on GET /hello : " + resp_data)
  115. if not test_val("Response mismatch", "/hello URI is not available", resp_data):
  116. raise AssertionError
  117. # Using same session for sending an HTTP request to /echo, as it is expected
  118. # that the custom error handler http_404_error_handler() would not have closed
  119. # the session
  120. sess.request("POST", url="/echo", body="Some content")
  121. resp = sess.getresponse()
  122. resp_data = resp.read().decode()
  123. # 404 Error must be returned from server as URI /hello is no longer available.
  124. # The custom error handler http_404_error_handler() will close the session
  125. # this time as the requested URI is /echo
  126. if not test_val("Status code mismatch", 404, resp.status):
  127. raise AssertionError
  128. # Compare error response string with expectation
  129. verbose_print(verbosity, "Response on POST /echo : " + resp_data)
  130. if not test_val("Response mismatch", "/echo URI is not available", resp_data):
  131. raise AssertionError
  132. try:
  133. # Using same session should fail as by now the session would have closed
  134. sess.request("POST", url="/hello", body="Some content")
  135. resp = sess.getresponse()
  136. resp.read().decode()
  137. # If control reaches this point then the socket was not closed.
  138. # This is not expected
  139. verbose_print(verbosity, "Socket not closed by server")
  140. raise AssertionError
  141. except http.client.HTTPException:
  142. # Catch socket error as we tried to communicate with an already closed socket
  143. pass
  144. except http.client.HTTPException:
  145. verbose_print(verbosity, "Socket closed by server")
  146. return False
  147. except AssertionError:
  148. return False
  149. finally:
  150. # Close HTTP connection
  151. sess.close()
  152. verbose_print(verbosity, "Enabling /hello handler")
  153. # Create new connection
  154. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  155. # PUT message to /ctrl to enable /hello URI handler
  156. # and restore 404 error handler to default
  157. sess.request("PUT", url="/ctrl", body="1")
  158. resp = sess.getresponse()
  159. resp.read()
  160. # Close HTTP connection
  161. sess.close()
  162. # Create new connection
  163. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  164. try:
  165. # Sending HTTP request to /hello should work now
  166. sess.request("GET", url="/hello")
  167. resp = sess.getresponse()
  168. resp_data = resp.read().decode()
  169. if not test_val("Status code mismatch", 200, resp.status):
  170. raise AssertionError
  171. verbose_print(verbosity, "Response on GET /hello : " + resp_data)
  172. if not test_val("Response mismatch", "Hello World!", resp_data):
  173. raise AssertionError
  174. # 404 Error handler should have been restored to default
  175. sess.request("GET", url="/invalid")
  176. resp = sess.getresponse()
  177. resp_data = resp.read().decode()
  178. if not test_val("Status code mismatch", 404, resp.status):
  179. raise AssertionError
  180. verbose_print(verbosity, "Response on GET /invalid : " + resp_data)
  181. if not test_val("Response mismatch", "This URI does not exist", resp_data):
  182. raise AssertionError
  183. except http.client.HTTPException:
  184. verbose_print(verbosity, "Socket closed by server")
  185. return False
  186. except AssertionError:
  187. return False
  188. finally:
  189. # Close HTTP connection
  190. sess.close()
  191. return True
  192. def test_custom_uri_query(ip, port, query, verbosity=False):
  193. verbose_print(verbosity, "======== GET HANDLER TEST =============")
  194. # Establish HTTP connection
  195. verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
  196. sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
  197. uri = "/hello?" + query
  198. # GET hello response
  199. verbose_print(verbosity, "Sending GET to URI : ", uri)
  200. sess.request("GET", url=uri, headers={})
  201. resp = sess.getresponse()
  202. resp_data = resp.read().decode()
  203. verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
  204. verbose_print(verbosity, "Server response to GET /hello")
  205. verbose_print(verbosity, "Response Data : " + resp_data)
  206. verbose_print(verbosity, "========================================\n")
  207. # Close HTTP connection
  208. sess.close()
  209. return "Hello World!" == resp_data
  210. if __name__ == '__main__':
  211. # Configure argument parser
  212. parser = argparse.ArgumentParser(description='Run HTTPd Test')
  213. parser.add_argument('IP', metavar='IP', type=str, help='Server IP')
  214. parser.add_argument('port', metavar='port', type=str, help='Server port')
  215. parser.add_argument('msg', metavar='message', type=str, help='Message to be sent to server')
  216. args = vars(parser.parse_args())
  217. # Get arguments
  218. ip = args['IP']
  219. port = args['port']
  220. msg = args['msg']
  221. if not (
  222. test_get_handler(ip, port, True) and
  223. test_put_handler(ip, port, True) and
  224. test_post_handler(ip, port, msg, True)
  225. ):
  226. Utility.console_log("Failed!")