pytest_simple_ota.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. # SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
  2. # SPDX-License-Identifier: Unlicense OR CC0-1.0
  3. import http.server
  4. import multiprocessing
  5. import os
  6. import ssl
  7. import subprocess
  8. import sys
  9. from typing import Tuple
  10. import pexpect
  11. import pytest
  12. from common_test_methods import get_env_config_variable, get_host_ip4_by_dest_ip
  13. from pytest_embedded import Dut
  14. server_cert = '-----BEGIN CERTIFICATE-----\n' \
  15. 'MIIDWDCCAkACCQCbF4+gVh/MLjANBgkqhkiG9w0BAQsFADBuMQswCQYDVQQGEwJJ\n'\
  16. 'TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\n'\
  17. 'VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\n'\
  18. 'b20wHhcNMjEwNzEyMTIzNjI3WhcNNDEwNzA3MTIzNjI3WjBuMQswCQYDVQQGEwJJ\n'\
  19. 'TjELMAkGA1UECAwCTUgxDDAKBgNVBAcMA1BVTjEMMAoGA1UECgwDRVNQMQwwCgYD\n'\
  20. 'VQQLDANFU1AxDDAKBgNVBAMMA0VTUDEaMBgGCSqGSIb3DQEJARYLZXNwQGVzcC5j\n'\
  21. 'b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhxF/y7bygndxPwiWL\n'\
  22. 'SwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQuc32W\n'\
  23. 'ukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2mKRbQ\n'\
  24. 'S5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO2fEz\n'\
  25. 'YaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnvL6Oz\n'\
  26. '3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdOAoap\n'\
  27. 'rFTRAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAItw24y565k3C/zENZlxyzto44ud\n'\
  28. 'IYPQXN8Fa2pBlLe1zlSIyuaA/rWQ+i1daS8nPotkCbWZyf5N8DYaTE4B0OfvoUPk\n'\
  29. 'B5uGDmbuk6akvlB5BGiYLfQjWHRsK9/4xjtIqN1H58yf3QNROuKsPAeywWS3Fn32\n'\
  30. '3//OpbWaClQePx6udRYMqAitKR+QxL7/BKZQsX+UyShuq8hjphvXvk0BW8ONzuw9\n'\
  31. 'RcoORxM0FzySYjeQvm4LhzC/P3ZBhEq0xs55aL2a76SJhq5hJy7T/Xz6NFByvlrN\n'\
  32. 'lFJJey33KFrAf5vnV9qcyWFIo7PYy2VsaaEjFeefr7q3sTFSMlJeadexW2Y=\n'\
  33. '-----END CERTIFICATE-----\n'
  34. server_key = '-----BEGIN PRIVATE KEY-----\n'\
  35. 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDhxF/y7bygndxP\n'\
  36. 'wiWLSwS9LY3uBMaJgup0ufNKVhx+FhGQOu44SghuJAaH3KkPUnt6SOM8jC97/yQu\n'\
  37. 'c32WukI7eBZoA12kargSnzdv5m5rZZpd+NznSSpoDArOAONKVlzr25A1+aZbix2m\n'\
  38. 'KRbQS5w9o1N2BriQuSzd8gL0Y0zEk3VkOWXEL+0yFUT144HnErnD+xnJtHe11yPO\n'\
  39. '2fEzYaGiilh0ddL26PXTugXMZN/8fRVHP50P2OG0SvFpC7vghlLp4VFM1/r3UJnv\n'\
  40. 'L6Oz3ALc6dhxZEKQucqlpj8l1UegszQToopemtIj0qXTHw2+uUnkUyWIPjPC+wdO\n'\
  41. 'AoaprFTRAgMBAAECggEAE0HCxV/N1Q1h+1OeDDGL5+74yjKSFKyb/vTVcaPCrmaH\n'\
  42. 'fPvp0ddOvMZJ4FDMAsiQS6/n4gQ7EKKEnYmwTqj4eUYW8yxGUn3f0YbPHbZT+Mkj\n'\
  43. 'z5woi3nMKi/MxCGDQZX4Ow3xUQlITUqibsfWcFHis8c4mTqdh4qj7xJzehD2PVYF\n'\
  44. 'gNHZsvVj6MltjBDAVwV1IlGoHjuElm6vuzkfX7phxcA1B4ZqdYY17yCXUnvui46z\n'\
  45. 'Xn2kUTOOUCEgfgvGa9E+l4OtdXi5IxjaSraU+dlg2KsE4TpCuN2MEVkeR5Ms3Y7Q\n'\
  46. 'jgJl8vlNFJDQpbFukLcYwG7rO5N5dQ6WWfVia/5XgQKBgQD74at/bXAPrh9NxPmz\n'\
  47. 'i1oqCHMDoM9sz8xIMZLF9YVu3Jf8ux4xVpRSnNy5RU1gl7ZXbpdgeIQ4v04zy5aw\n'\
  48. '8T4tu9K3XnR3UXOy25AK0q+cnnxZg3kFQm+PhtOCKEFjPHrgo2MUfnj+EDddod7N\n'\
  49. 'JQr9q5rEFbqHupFPpWlqCa3QmQKBgQDldWUGokNaEpmgHDMnHxiibXV5LQhzf8Rq\n'\
  50. 'gJIQXb7R9EsTSXEvsDyqTBb7PHp2Ko7rZ5YQfyf8OogGGjGElnPoU/a+Jij1gVFv\n'\
  51. 'kZ064uXAAISBkwHdcuobqc5EbG3ceyH46F+FBFhqM8KcbxJxx08objmh58+83InN\n'\
  52. 'P9Qr25Xw+QKBgEGXMHuMWgQbSZeM1aFFhoMvlBO7yogBTKb4Ecpu9wI5e3Kan3Al\n'\
  53. 'pZYltuyf+VhP6XG3IMBEYdoNJyYhu+nzyEdMg8CwXg+8LC7FMis/Ve+o7aS5scgG\n'\
  54. '1to/N9DK/swCsdTRdzmc/ZDbVC+TuVsebFBGYZTyO5KgqLpezqaIQrTxAoGALFCU\n'\
  55. '10glO9MVyl9H3clap5v+MQ3qcOv/EhaMnw6L2N6WVT481tnxjW4ujgzrFcE4YuxZ\n'\
  56. 'hgwYu9TOCmeqopGwBvGYWLbj+C4mfSahOAs0FfXDoYazuIIGBpuv03UhbpB1Si4O\n'\
  57. 'rJDfRnuCnVWyOTkl54gKJ2OusinhjztBjcrV1XkCgYEA3qNi4uBsPdyz9BZGb/3G\n'\
  58. 'rOMSw0CaT4pEMTLZqURmDP/0hxvTk1polP7O/FYwxVuJnBb6mzDa0xpLFPTpIAnJ\n'\
  59. 'YXB8xpXU69QVh+EBbemdJWOd+zp5UCfXvb2shAeG3Tn/Dz4cBBMEUutbzP+or0nG\n'\
  60. 'vSXnRLaxQhooWm+IuX9SuBQ=\n'\
  61. '-----END PRIVATE KEY-----\n'
  62. def start_https_server(ota_image_dir: str, server_ip: str, server_port: int, server_file: str = None, key_file: str = None) -> None:
  63. os.chdir(ota_image_dir)
  64. if server_file is None:
  65. server_file = os.path.join(ota_image_dir, 'server_cert.pem')
  66. cert_file_handle = open(server_file, 'w+')
  67. cert_file_handle.write(server_cert)
  68. cert_file_handle.close()
  69. if key_file is None:
  70. key_file = os.path.join(ota_image_dir, 'server_key.pem')
  71. key_file_handle = open('server_key.pem', 'w+')
  72. key_file_handle.write(server_key)
  73. key_file_handle.close()
  74. httpd = http.server.HTTPServer((server_ip, server_port), http.server.SimpleHTTPRequestHandler)
  75. httpd.socket = ssl.wrap_socket(httpd.socket,
  76. keyfile=key_file,
  77. certfile=server_file, server_side=True)
  78. httpd.serve_forever()
  79. def start_tls1_3_server(ota_image_dir: str, server_port: int) -> subprocess.Popen:
  80. os.chdir(ota_image_dir)
  81. server_file = os.path.join(ota_image_dir, 'server_cert.pem')
  82. cert_file_handle = open(server_file, 'w+')
  83. cert_file_handle.write(server_cert)
  84. cert_file_handle.close()
  85. key_file = os.path.join(ota_image_dir, 'server_key.pem')
  86. key_file_handle = open('server_key.pem', 'w+')
  87. key_file_handle.write(server_key)
  88. key_file_handle.close()
  89. chunked_server = subprocess.Popen(['openssl', 's_server', '-tls1_3', '-WWW', '-key', key_file, '-cert', server_file, '-port', str(server_port)])
  90. return chunked_server
  91. def check_sha256(sha256_expected: str, sha256_reported: str) -> None:
  92. print('sha256_expected: %s' % (sha256_expected))
  93. print('sha256_reported: %s' % (sha256_reported))
  94. if sha256_expected not in sha256_reported:
  95. raise ValueError('SHA256 mismatch')
  96. else:
  97. print('SHA256 expected and reported are the same')
  98. def calc_all_sha256(dut: Dut) -> Tuple[str, str]:
  99. bootloader_path = os.path.join(dut.app.binary_path, 'bootloader', 'bootloader.bin')
  100. sha256_bootloader = dut.app.get_sha256(bootloader_path)
  101. app_path = os.path.join(dut.app.binary_path, 'simple_ota.bin')
  102. sha256_app = dut.app.get_sha256(app_path)
  103. return str(sha256_bootloader), str(sha256_app)
  104. @pytest.mark.esp32
  105. @pytest.mark.esp32c3
  106. @pytest.mark.esp32s2
  107. @pytest.mark.esp32s3
  108. @pytest.mark.wifi_high_traffic
  109. def test_examples_protocol_simple_ota_example(dut: Dut) -> None:
  110. """
  111. steps: |
  112. 1. join AP/Ethernet
  113. 2. Fetch OTA image over HTTPS
  114. 3. Reboot with the new OTA image
  115. """
  116. sha256_bootloader, sha256_app = calc_all_sha256(dut)
  117. # Start server
  118. thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', 8000))
  119. thread1.daemon = True
  120. thread1.start()
  121. try:
  122. # start test
  123. dut.expect('Loaded app from partition at offset 0x10000', timeout=30)
  124. check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0]))
  125. check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0]))
  126. # Parse IP address of STA
  127. if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
  128. env_name = 'wifi_high_traffic'
  129. dut.expect('Please input ssid password:')
  130. ap_ssid = get_env_config_variable(env_name, 'ap_ssid')
  131. ap_password = get_env_config_variable(env_name, 'ap_password')
  132. dut.write(f'{ap_ssid} {ap_password}')
  133. try:
  134. ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
  135. print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
  136. except pexpect.exceptions.TIMEOUT:
  137. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
  138. host_ip = get_host_ip4_by_dest_ip(ip_address)
  139. dut.expect('Starting OTA example task', timeout=30)
  140. print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
  141. dut.write('https://' + host_ip + ':8000/simple_ota.bin')
  142. dut.expect('OTA Succeed, Rebooting...', timeout=60)
  143. # after reboot
  144. dut.expect('Loaded app from partition at offset 0x110000', timeout=30)
  145. dut.expect('OTA example app_main start', timeout=10)
  146. finally:
  147. thread1.terminate()
  148. @pytest.mark.esp32
  149. @pytest.mark.esp32c3
  150. @pytest.mark.esp32s2
  151. @pytest.mark.esp32s3
  152. @pytest.mark.ethernet_ota
  153. @pytest.mark.parametrize('config', ['spiram',], indirect=True)
  154. def test_examples_protocol_simple_ota_example_ethernet_with_spiram_config(dut: Dut) -> None:
  155. """
  156. steps: |
  157. 1. join AP/Ethernet
  158. 2. Fetch OTA image over HTTPS
  159. 3. Reboot with the new OTA image
  160. """
  161. # Start server
  162. thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', 8000))
  163. thread1.daemon = True
  164. thread1.start()
  165. try:
  166. # start test
  167. dut.expect('Loaded app from partition at offset 0x10000', timeout=30)
  168. try:
  169. ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
  170. print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
  171. except pexpect.exceptions.TIMEOUT:
  172. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
  173. host_ip = get_host_ip4_by_dest_ip(ip_address)
  174. dut.expect('Starting OTA example task', timeout=30)
  175. print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
  176. dut.write('https://' + host_ip + ':8000/simple_ota.bin')
  177. dut.expect('OTA Succeed, Rebooting...', timeout=60)
  178. # after reboot
  179. dut.expect('Loaded app from partition at offset 0x110000', timeout=30)
  180. dut.expect('OTA example app_main start', timeout=10)
  181. finally:
  182. thread1.terminate()
  183. @pytest.mark.esp32
  184. @pytest.mark.esp32c3
  185. @pytest.mark.flash_encryption_wifi_high_traffic
  186. @pytest.mark.nightly_run
  187. @pytest.mark.parametrize('config', ['flash_enc_wifi',], indirect=True)
  188. @pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True)
  189. def test_examples_protocol_simple_ota_example_with_flash_encryption_wifi(dut: Dut) -> None:
  190. """
  191. steps: |
  192. 1. join AP/Ethernet
  193. 2. Fetch OTA image over HTTPS
  194. 3. Reboot with the new OTA image
  195. """
  196. # start test
  197. # Erase flash
  198. dut.serial.erase_flash()
  199. dut.serial.flash()
  200. # Start server
  201. thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', 8000))
  202. thread1.daemon = True
  203. thread1.start()
  204. try:
  205. dut.expect('Loaded app from partition at offset 0x20000', timeout=30)
  206. dut.expect('Flash encryption mode is DEVELOPMENT', timeout=10)
  207. # Parse IP address of STA
  208. if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
  209. env_name = 'flash_encryption_wifi_high_traffic'
  210. dut.expect('Please input ssid password:')
  211. ap_ssid = get_env_config_variable(env_name, 'ap_ssid')
  212. ap_password = get_env_config_variable(env_name, 'ap_password')
  213. dut.write(f'{ap_ssid} {ap_password}')
  214. try:
  215. ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
  216. print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
  217. except pexpect.exceptions.TIMEOUT:
  218. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
  219. host_ip = get_host_ip4_by_dest_ip(ip_address)
  220. dut.expect('Starting OTA example task', timeout=30)
  221. print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
  222. dut.write('https://' + host_ip + ':8000/simple_ota.bin')
  223. dut.expect('OTA Succeed, Rebooting...', timeout=60)
  224. # after reboot
  225. dut.expect('Loaded app from partition at offset 0x120000', timeout=30)
  226. dut.expect('Flash encryption mode is DEVELOPMENT', timeout=10)
  227. dut.expect('OTA example app_main start', timeout=10)
  228. finally:
  229. thread1.terminate()
  230. @pytest.mark.esp32
  231. @pytest.mark.esp32c3
  232. @pytest.mark.esp32s2
  233. @pytest.mark.esp32s3
  234. @pytest.mark.ethernet_ota
  235. @pytest.mark.parametrize('config', ['on_update_no_sb_ecdsa',], indirect=True)
  236. def test_examples_protocol_simple_ota_example_with_verify_app_signature_on_update_no_secure_boot_ecdsa(dut: Dut) -> None:
  237. """
  238. steps: |
  239. 1. join AP/Ethernet
  240. 2. Fetch OTA image over HTTPS
  241. 3. Reboot with the new OTA image
  242. """
  243. sha256_bootloader, sha256_app = calc_all_sha256(dut)
  244. # Start server
  245. thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', 8000))
  246. thread1.daemon = True
  247. thread1.start()
  248. try:
  249. # start test
  250. dut.expect('Loaded app from partition at offset 0x20000', timeout=30)
  251. check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0]))
  252. check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0]))
  253. try:
  254. ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
  255. print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
  256. except pexpect.exceptions.TIMEOUT:
  257. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
  258. host_ip = get_host_ip4_by_dest_ip(ip_address)
  259. dut.expect('Starting OTA example task', timeout=30)
  260. print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
  261. dut.write('https://' + host_ip + ':8000/simple_ota.bin')
  262. dut.expect('Writing to partition subtype 16 at offset 0x120000', timeout=20)
  263. dut.expect('Verifying image signature...', timeout=60)
  264. dut.expect('OTA Succeed, Rebooting...', timeout=60)
  265. # after reboot
  266. dut.expect('Loaded app from partition at offset 0x120000', timeout=20)
  267. dut.expect('OTA example app_main start', timeout=10)
  268. finally:
  269. thread1.terminate()
  270. @pytest.mark.esp32
  271. @pytest.mark.esp32c3
  272. @pytest.mark.esp32s2
  273. @pytest.mark.esp32s3
  274. @pytest.mark.ethernet_ota
  275. @pytest.mark.parametrize('config', ['on_update_no_sb_rsa',], indirect=True)
  276. def test_examples_protocol_simple_ota_example_with_verify_app_signature_on_update_no_secure_boot_rsa(dut: Dut) -> None:
  277. """
  278. steps: |
  279. 1. join AP/Ethernet
  280. 2. Fetch OTA image over HTTPS
  281. 3. Reboot with the new OTA image
  282. """
  283. sha256_bootloader, sha256_app = calc_all_sha256(dut)
  284. # Start server
  285. thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, '0.0.0.0', 8000))
  286. thread1.daemon = True
  287. thread1.start()
  288. try:
  289. # start test
  290. dut.expect('Loaded app from partition at offset 0x20000', timeout=30)
  291. check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0]))
  292. check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0]))
  293. try:
  294. ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
  295. print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
  296. except pexpect.exceptions.TIMEOUT:
  297. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
  298. host_ip = get_host_ip4_by_dest_ip(ip_address)
  299. dut.expect('Starting OTA example task', timeout=30)
  300. print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
  301. dut.write('https://' + host_ip + ':8000/simple_ota.bin')
  302. dut.expect('Writing to partition subtype 16 at offset 0x120000', timeout=20)
  303. dut.expect('Verifying image signature...', timeout=60)
  304. dut.expect('#0 app key digest == #0 trusted key digest', timeout=10)
  305. dut.expect('Verifying with RSA-PSS...', timeout=10)
  306. dut.expect('Signature verified successfully!', timeout=10)
  307. dut.expect('OTA Succeed, Rebooting...', timeout=60)
  308. # after reboot
  309. dut.expect('Loaded app from partition at offset 0x120000', timeout=20)
  310. dut.expect('OTA example app_main start', timeout=10)
  311. finally:
  312. thread1.terminate()
  313. @pytest.mark.esp32
  314. @pytest.mark.ethernet_ota
  315. @pytest.mark.parametrize('config', ['tls1_3',], indirect=True)
  316. def test_examples_protocol_simple_ota_example_tls1_3(dut: Dut) -> None:
  317. """
  318. steps: |
  319. 1. join AP/Ethernet
  320. 2. Fetch OTA image over HTTPS
  321. 3. Reboot with the new OTA image
  322. """
  323. sha256_bootloader, sha256_app = calc_all_sha256(dut)
  324. # Start server
  325. tls1_3_server = start_tls1_3_server(dut.app.binary_path, 8000)
  326. try:
  327. # start test
  328. dut.expect('Loaded app from partition at offset 0x10000', timeout=30)
  329. check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0]))
  330. check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0]))
  331. # Parse IP address of STA
  332. if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
  333. env_name = 'wifi_high_traffic'
  334. dut.expect('Please input ssid password:')
  335. ap_ssid = get_env_config_variable(env_name, 'ap_ssid')
  336. ap_password = get_env_config_variable(env_name, 'ap_password')
  337. dut.write(f'{ap_ssid} {ap_password}')
  338. try:
  339. ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)[^\d]', timeout=30)[1].decode()
  340. print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
  341. except pexpect.exceptions.TIMEOUT:
  342. raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
  343. host_ip = get_host_ip4_by_dest_ip(ip_address)
  344. dut.expect('Starting OTA example task', timeout=30)
  345. print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
  346. dut.write('https://' + host_ip + ':8000/simple_ota.bin')
  347. dut.expect('OTA Succeed, Rebooting...', timeout=120)
  348. # after reboot
  349. dut.expect('Loaded app from partition at offset 0x110000', timeout=30)
  350. dut.expect('OTA example app_main start', timeout=10)
  351. finally:
  352. tls1_3_server.kill()
  353. if __name__ == '__main__':
  354. if sys.argv[2:]: # if two or more arguments provided:
  355. # Usage: pytest_simple_ota.py <image_dir> <server_port> [cert_di>]
  356. this_dir = os.path.dirname(os.path.realpath(__file__))
  357. bin_dir = os.path.join(this_dir, sys.argv[1])
  358. port = int(sys.argv[2])
  359. cert_dir = bin_dir if not sys.argv[3:] else os.path.join(this_dir, sys.argv[3]) # optional argument
  360. print('Starting HTTPS server at "https://:{}"'.format(port))
  361. start_https_server(bin_dir, '', port,
  362. server_file=os.path.join(cert_dir, 'ca_cert.pem'),
  363. key_file=os.path.join(cert_dir, 'ca_key.pem'))