example_test.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. import re
  2. import os
  3. import socket
  4. import BaseHTTPServer
  5. import SimpleHTTPServer
  6. from threading import Thread
  7. import ssl
  8. from tiny_test_fw import DUT
  9. import ttfw_idf
  10. import random
  11. server_cert = "-----BEGIN CERTIFICATE-----\n" \
  12. "MIIDXTCCAkWgAwIBAgIJAP4LF7E72HakMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\n"\
  13. "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX\n"\
  14. "aWRnaXRzIFB0eSBMdGQwHhcNMTkwNjA3MDk1OTE2WhcNMjAwNjA2MDk1OTE2WjBF\n"\
  15. "MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50\n"\
  16. "ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"\
  17. "CgKCAQEAlzfCyv3mIv7TlLkObxunKfCdrJ/zgdANrsx0RBtpEPhV560hWJ0fEin0\n"\
  18. "nIOMpJSiF9E6QsPdr6Q+eogH4XnOMU9JE+iG743N1dPfGEzJvRlyct/Ck8SswKPC\n"\
  19. "9+VXsnOdZmUw9y/xtANbURA/TspvPzz3Avv382ffffrJGh7ooOmaZSCZFlSYHLZA\n"\
  20. "w/XlRr0sSRbLpFGY0gXjaAV8iHHiPDYLy4kZOepjV9U51xi+IGsL4w75zuMgsHyF\n"\
  21. "3nJeGYHgtGVBrkL0ZKG5udY0wcBjysjubDJC4iSlNiq2HD3fhs7j6CZddV2v845M\n"\
  22. "lVKNxP0kO4Uj4D8r+5USWC8JKfAwxQIDAQABo1AwTjAdBgNVHQ4EFgQU6OE7ssfY\n"\
  23. "IIPTDThiUoofUpsD5NwwHwYDVR0jBBgwFoAU6OE7ssfYIIPTDThiUoofUpsD5Nww\n"\
  24. "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAXIlHS/FJWfmcinUAxyBd\n"\
  25. "/xd5Lu8ykeru6oaUCci+Vk9lyoMMES7lQ+b/00d5x7AcTawkTil9EWpBTPTOTraA\n"\
  26. "lzJMQhNKmSLk0iIoTtAJtSZgUSpIIozqK6lenxQQDsHbXKU6h+u9H6KZE8YcjsFl\n"\
  27. "6vL7sw9BVotw/VxfgjQ5OSGLgoLrdVT0z5C2qOuwOgz1c7jNiJhtMdwN+cOtnJp2\n"\
  28. "fuBgEYyE3eeuWogvkWoDcIA8r17Ixzkpq2oJsdvZcHZPIZShPKW2SHUsl98KDemu\n"\
  29. "y0pQyExmQUbwKE4vbFb9XuWCcL9XaOHQytyszt2DeD67AipvoBwVU7/LBOvqnsmy\n"\
  30. "hA==\n"\
  31. "-----END CERTIFICATE-----\n"
  32. server_key = "-----BEGIN PRIVATE KEY-----\n"\
  33. "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCXN8LK/eYi/tOU\n"\
  34. "uQ5vG6cp8J2sn/OB0A2uzHREG2kQ+FXnrSFYnR8SKfScg4yklKIX0TpCw92vpD56\n"\
  35. "iAfhec4xT0kT6Ibvjc3V098YTMm9GXJy38KTxKzAo8L35Veyc51mZTD3L/G0A1tR\n"\
  36. "ED9Oym8/PPcC+/fzZ999+skaHuig6ZplIJkWVJgctkDD9eVGvSxJFsukUZjSBeNo\n"\
  37. "BXyIceI8NgvLiRk56mNX1TnXGL4gawvjDvnO4yCwfIXecl4ZgeC0ZUGuQvRkobm5\n"\
  38. "1jTBwGPKyO5sMkLiJKU2KrYcPd+GzuPoJl11Xa/zjkyVUo3E/SQ7hSPgPyv7lRJY\n"\
  39. "Lwkp8DDFAgMBAAECggEAfBhAfQE7mUByNbxgAgI5fot9eaqR1Nf+QpJ6X2H3KPwC\n"\
  40. "02sa0HOwieFwYfj6tB1doBoNq7i89mTc+QUlIn4pHgIowHO0OGawomeKz5BEhjCZ\n"\
  41. "4XeLYGSoODary2+kNkf2xY8JTfFEcyvGBpJEwc4S2VyYgRRx+IgnumTSH+N5mIKZ\n"\
  42. "SXWNdZIuHEmkwod+rPRXs6/r+PH0eVW6WfpINEbr4zVAGXJx2zXQwd2cuV1GTJWh\n"\
  43. "cPVOXLu+XJ9im9B370cYN6GqUnR3fui13urYbnWnEf3syvoH/zuZkyrVChauoFf8\n"\
  44. "8EGb74/HhXK7Q2s8NRakx2c7OxQifCbcy03liUMmyQKBgQDFAob5B/66N4Q2cq/N\n"\
  45. "MWPf98kYBYoLaeEOhEJhLQlKk0pIFCTmtpmUbpoEes2kCUbH7RwczpYko8tlKyoB\n"\
  46. "6Fn6RY4zQQ64KZJI6kQVsjkYpcP/ihnOY6rbds+3yyv+4uPX7Eh9sYZwZMggE19M\n"\
  47. "CkFHkwAjiwqhiiSlUxe20sWmowKBgQDEfx4lxuFzA1PBPeZKGVBTxYPQf+DSLCre\n"\
  48. "ZFg3ZmrxbCjRq1O7Lra4FXWD3dmRq7NDk79JofoW50yD8wD7I0B7opdDfXD2idO8\n"\
  49. "0dBnWUKDr2CAXyoLEINce9kJPbx4kFBQRN9PiGF7VkDQxeQ3kfS8CvcErpTKCOdy\n"\
  50. "5wOwBTwJdwKBgDiTFTeGeDv5nVoVbS67tDao7XKchJvqd9q3WGiXikeELJyuTDqE\n"\
  51. "zW22pTwMF+m3UEAxcxVCrhMvhkUzNAkANHaOatuFHzj7lyqhO5QPbh4J3FMR0X9X\n"\
  52. "V8VWRSg+jA/SECP9koOl6zlzd5Tee0tW1pA7QpryXscs6IEhb3ns5R2JAoGAIkzO\n"\
  53. "RmnhEOKTzDex611f2D+yMsMfy5BKK2f4vjLymBH5TiBKDXKqEpgsW0huoi8Gq9Uu\n"\
  54. "nvvXXAgkIyRYF36f0vUe0nkjLuYAQAWgC2pZYgNLJR13iVbol0xHJoXQUHtgiaJ8\n"\
  55. "GLYFzjHQPqFMpSalQe3oELko39uOC1CoJCHFySECgYBeycUnRBikCO2n8DNhY4Eg\n"\
  56. "9Y3oxcssRt6ea5BZwgW2eAYi7/XqKkmxoSoOykUt3MJx9+EkkrL17bxFSpkj1tvL\n"\
  57. "qvxn7egtsKjjgGNAxwXC4MwCvhveyUQQxtQb8AqGrGqo4jEEN0L15cnP38i2x1Uo\n"\
  58. "muhfskWf4MABV0yTUaKcGg==\n"\
  59. "-----END PRIVATE KEY-----\n"
  60. def get_my_ip():
  61. s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  62. s1.connect(("8.8.8.8", 80))
  63. my_ip = s1.getsockname()[0]
  64. s1.close()
  65. return my_ip
  66. def start_https_server(ota_image_dir, server_ip, server_port):
  67. os.chdir(ota_image_dir)
  68. server_file = os.path.join(ota_image_dir, "server_cert.pem")
  69. cert_file_handle = open(server_file, "w+")
  70. cert_file_handle.write(server_cert)
  71. cert_file_handle.close()
  72. key_file = os.path.join(ota_image_dir, "server_key.pem")
  73. key_file_handle = open("server_key.pem", "w+")
  74. key_file_handle.write(server_key)
  75. key_file_handle.close()
  76. httpd = BaseHTTPServer.HTTPServer((server_ip, server_port),
  77. SimpleHTTPServer.SimpleHTTPRequestHandler)
  78. httpd.socket = ssl.wrap_socket(httpd.socket,
  79. keyfile=key_file,
  80. certfile=server_file, server_side=True)
  81. httpd.serve_forever()
  82. @ttfw_idf.idf_example_test(env_tag="Example_WIFI")
  83. def test_examples_protocol_advanced_https_ota_example(env, extra_data):
  84. """
  85. This is a positive test case, which downloads complete binary file multiple number of times.
  86. Number of iterations can be specified in variable iterations.
  87. steps: |
  88. 1. join AP
  89. 2. Fetch OTA image over HTTPS
  90. 3. Reboot with the new OTA image
  91. """
  92. dut1 = env.get_dut("advanced_https_ota_example", "examples/system/ota/advanced_https_ota", dut_class=ttfw_idf.ESP32DUT)
  93. # Number of iterations to validate OTA
  94. iterations = 3
  95. # File to be downloaded. This file is generated after compilation
  96. bin_name = "advanced_https_ota.bin"
  97. # check and log bin size
  98. binary_file = os.path.join(dut1.app.binary_path, bin_name)
  99. bin_size = os.path.getsize(binary_file)
  100. ttfw_idf.log_performance("advanced_https_ota_bin_size", "{}KB".format(bin_size // 1024))
  101. ttfw_idf.check_performance("advanced_https_ota_bin_size", bin_size // 1024)
  102. # start test
  103. host_ip = get_my_ip()
  104. thread1 = Thread(target=start_https_server, args=(dut1.app.binary_path, host_ip, 8001))
  105. thread1.daemon = True
  106. thread1.start()
  107. dut1.start_app()
  108. for i in range(iterations):
  109. dut1.expect("Loaded app from partition at offset", timeout=30)
  110. try:
  111. ip_address = dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30)
  112. print("Connected to AP with IP: {}".format(ip_address))
  113. except DUT.ExpectTimeout:
  114. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
  115. thread1.close()
  116. dut1.expect("Starting Advanced OTA example", timeout=30)
  117. print("writing to device: {}".format("https://" + host_ip + ":8001/" + bin_name))
  118. dut1.write("https://" + host_ip + ":8001/" + bin_name)
  119. dut1.expect("Loaded app from partition at offset", timeout=60)
  120. dut1.expect("Starting Advanced OTA example", timeout=30)
  121. dut1.reset()
  122. @ttfw_idf.idf_example_test(env_tag="Example_WIFI")
  123. def test_examples_protocol_advanced_https_ota_example_truncated_bin(env, extra_data):
  124. """
  125. Working of OTA if binary file is truncated is validated in this test case.
  126. Application should return with error message in this case.
  127. steps: |
  128. 1. join AP
  129. 2. Generate truncated binary file
  130. 3. Fetch OTA image over HTTPS
  131. 4. Check working of code if bin is truncated
  132. """
  133. dut1 = env.get_dut("advanced_https_ota_example", "examples/system/ota/advanced_https_ota", dut_class=ttfw_idf.ESP32DUT)
  134. # Original binary file generated after compilation
  135. bin_name = "advanced_https_ota.bin"
  136. # Truncated binary file to be generated from original binary file
  137. truncated_bin_name = "truncated.bin"
  138. # Size of truncated file to be grnerated. This value can range from 288 bytes (Image header size) to size of original binary file
  139. # truncated_bin_size is set to 64000 to reduce consumed by the test case
  140. truncated_bin_size = 64000
  141. # check and log bin size
  142. binary_file = os.path.join(dut1.app.binary_path, bin_name)
  143. f = open(binary_file, "r+")
  144. fo = open(os.path.join(dut1.app.binary_path, truncated_bin_name), "w+")
  145. fo.write(f.read(truncated_bin_size))
  146. fo.close()
  147. f.close()
  148. binary_file = os.path.join(dut1.app.binary_path, truncated_bin_name)
  149. bin_size = os.path.getsize(binary_file)
  150. ttfw_idf.log_performance("advanced_https_ota_bin_size", "{}KB".format(bin_size // 1024))
  151. ttfw_idf.check_performance("advanced_https_ota_bin_size", bin_size // 1024)
  152. # start test
  153. host_ip = get_my_ip()
  154. dut1.start_app()
  155. dut1.expect("Loaded app from partition at offset", timeout=30)
  156. try:
  157. ip_address = dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30)
  158. print("Connected to AP with IP: {}".format(ip_address))
  159. except DUT.ExpectTimeout:
  160. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
  161. dut1.expect("Starting Advanced OTA example", timeout=30)
  162. print("writing to device: {}".format("https://" + host_ip + ":8001/" + truncated_bin_name))
  163. dut1.write("https://" + host_ip + ":8001/" + truncated_bin_name)
  164. dut1.expect("Image validation failed, image is corrupted", timeout=30)
  165. @ttfw_idf.idf_example_test(env_tag="Example_WIFI")
  166. def test_examples_protocol_advanced_https_ota_example_truncated_header(env, extra_data):
  167. """
  168. Working of OTA if headers of binary file are truncated is vaildated in this test case.
  169. Application should return with error message in this case.
  170. steps: |
  171. 1. join AP
  172. 2. Generate binary file with truncated headers
  173. 3. Fetch OTA image over HTTPS
  174. 4. Check working of code if headers are not sent completely
  175. """
  176. dut1 = env.get_dut("advanced_https_ota_example", "examples/system/ota/advanced_https_ota", dut_class=ttfw_idf.ESP32DUT)
  177. # Original binary file generated after compilation
  178. bin_name = "advanced_https_ota.bin"
  179. # Truncated binary file to be generated from original binary file
  180. truncated_bin_name = "truncated_header.bin"
  181. # Size of truncated file to be grnerated. This value should be less than 288 bytes (Image header size)
  182. truncated_bin_size = 180
  183. # check and log bin size
  184. binary_file = os.path.join(dut1.app.binary_path, bin_name)
  185. f = open(binary_file, "r+")
  186. fo = open(os.path.join(dut1.app.binary_path, truncated_bin_name), "w+")
  187. fo.write(f.read(truncated_bin_size))
  188. fo.close()
  189. f.close()
  190. binary_file = os.path.join(dut1.app.binary_path, truncated_bin_name)
  191. bin_size = os.path.getsize(binary_file)
  192. ttfw_idf.log_performance("advanced_https_ota_bin_size", "{}KB".format(bin_size // 1024))
  193. ttfw_idf.check_performance("advanced_https_ota_bin_size", bin_size // 1024)
  194. # start test
  195. host_ip = get_my_ip()
  196. dut1.start_app()
  197. dut1.expect("Loaded app from partition at offset", timeout=30)
  198. try:
  199. ip_address = dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30)
  200. print("Connected to AP with IP: {}".format(ip_address))
  201. except DUT.ExpectTimeout:
  202. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
  203. dut1.expect("Starting Advanced OTA example", timeout=30)
  204. print("writing to device: {}".format("https://" + host_ip + ":8001/" + truncated_bin_name))
  205. dut1.write("https://" + host_ip + ":8001/" + truncated_bin_name)
  206. dut1.expect("advanced_https_ota_example: esp_https_ota_read_img_desc failed", timeout=30)
  207. @ttfw_idf.idf_example_test(env_tag="Example_WIFI")
  208. def test_examples_protocol_advanced_https_ota_example_random(env, extra_data):
  209. """
  210. Working of OTA if random data is added in binary file are validated in this test case.
  211. Magic byte verification should fail in this case.
  212. steps: |
  213. 1. join AP
  214. 2. Generate random binary image
  215. 3. Fetch OTA image over HTTPS
  216. 4. Check working of code for random binary file
  217. """
  218. dut1 = env.get_dut("advanced_https_ota_example", "examples/system/ota/advanced_https_ota", dut_class=ttfw_idf.ESP32DUT)
  219. # Random binary file to be generated
  220. random_bin_name = "random.bin"
  221. # Size of random binary file. 32000 is choosen, to reduce the time required to run the test-case
  222. random_bin_size = 32000
  223. # check and log bin size
  224. binary_file = os.path.join(dut1.app.binary_path, random_bin_name)
  225. fo = open(binary_file, "w+")
  226. # First byte of binary file is always set to zero. If first byte is generated randomly,
  227. # in some cases it may generate 0xE9 which will result in failure of testcase.
  228. fo.write(str(0))
  229. for i in range(random_bin_size - 1):
  230. fo.write(str(random.randrange(0,255,1)))
  231. fo.close()
  232. bin_size = os.path.getsize(binary_file)
  233. ttfw_idf.log_performance("advanced_https_ota_bin_size", "{}KB".format(bin_size // 1024))
  234. ttfw_idf.check_performance("advanced_https_ota_bin_size", bin_size // 1024)
  235. # start test
  236. host_ip = get_my_ip()
  237. dut1.start_app()
  238. dut1.expect("Loaded app from partition at offset", timeout=30)
  239. try:
  240. ip_address = dut1.expect(re.compile(r" sta ip: ([^,]+),"), timeout=30)
  241. print("Connected to AP with IP: {}".format(ip_address))
  242. except DUT.ExpectTimeout:
  243. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
  244. dut1.expect("Starting Advanced OTA example", timeout=30)
  245. print("writing to device: {}".format("https://" + host_ip + ":8001/" + random_bin_name))
  246. dut1.write("https://" + host_ip + ":8001/" + random_bin_name)
  247. dut1.expect("esp_ota_ops: OTA image has invalid magic byte", timeout=10)
  248. if __name__ == '__main__':
  249. test_examples_protocol_advanced_https_ota_example()
  250. test_examples_protocol_advanced_https_ota_example_truncated_bin()
  251. test_examples_protocol_advanced_https_ota_example_truncated_header()
  252. test_examples_protocol_advanced_https_ota_example_random()