CI: update test cases to use different environment variables

change test environments
optimize asio udp server test
fix icmp echo test case
use ethernet_router env to run iperf test cases
This commit is contained in:
Chen Yudong
2022-07-03 16:22:20 +08:00
parent 5d0302e49f
commit 472ac26712
38 changed files with 788 additions and 796 deletions

View File

@@ -11,8 +11,14 @@
reports: reports:
junit: XUNIT_RESULT.xml junit: XUNIT_RESULT.xml
expire_in: 1 week expire_in: 1 week
variables:
GIT_DEPTH: 1
script: script:
- retry_failed git clone $KNOWN_FAILURE_CASES_REPO known_failure_cases - retry_failed git clone $KNOWN_FAILURE_CASES_REPO known_failure_cases
# get runner env config file
- retry_failed git clone $TEST_ENV_CONFIG_REPO
- python $CHECKOUT_REF_SCRIPT ci-test-runner-configs ci-test-runner-configs
- cp ./ci-test-runner-configs/${CI_RUNNER_DESCRIPTION}/EnvConfig.yml EnvConfig.yml || true
# using runner tags as markers to filter the test cases # using runner tags as markers to filter the test cases
# Runner tags are comma separated, replace the comma with " and " for markers # Runner tags are comma separated, replace the comma with " and " for markers
- job_tags=$(python tools/ci/python_packages/gitlab_api.py get_job_tags $CI_PROJECT_ID --job_id $CI_JOB_ID) - job_tags=$(python tools/ci/python_packages/gitlab_api.py get_job_tags $CI_PROJECT_ID --job_id $CI_JOB_ID)
@@ -80,13 +86,13 @@ example_test_pytest_esp32c3_flash_suspend:
- build_pytest_examples_esp32c3 - build_pytest_examples_esp32c3
tags: [ esp32c3, flash_suspend ] tags: [ esp32c3, flash_suspend ]
example_test_pytest_esp32_ethernet_ota: example_test_pytest_esp32_ethernet_router:
extends: extends:
- .pytest_examples_dir_template - .pytest_examples_dir_template
- .rules:test:example_test-esp32-ota-related_changes - .rules:test:example_test-esp32-ota-related_changes
needs: needs:
- build_pytest_examples_esp32 - build_pytest_examples_esp32
tags: [ esp32, ethernet_ota ] tags: [ esp32, ethernet_router ]
example_test_pytest_esp32_wifi_ota: example_test_pytest_esp32_wifi_ota:
extends: extends:
@@ -128,21 +134,29 @@ example_test_pytest_esp32_8mb_flash:
- build_pytest_examples_esp32 - build_pytest_examples_esp32
tags: [ esp32, ethernet_flash_8m ] tags: [ esp32, ethernet_flash_8m ]
example_test_pytest_esp32_wifi: example_test_pytest_esp32_wifi_nearby:
extends: extends:
- .pytest_examples_dir_template - .pytest_examples_dir_template
- .rules:test:example_test-esp32-wifi-related_changes - .rules:test:example_test-esp32-wifi-related_changes
needs: needs:
- build_pytest_examples_esp32 - build_pytest_examples_esp32
tags: [ esp32, wifi ] tags: [ esp32, wifi_nearby ]
example_test_pytest_esp32_wifi_bt: example_test_pytest_esp32_wifi_router:
extends: extends:
- .pytest_examples_dir_template - .pytest_examples_dir_template
- .rules:test:example_test-esp32 - .rules:test:example_test-esp32
needs: needs:
- build_pytest_examples_esp32 - build_pytest_examples_esp32
tags: [ esp32, wifi_bt ] tags: [ esp32, wifi_router ]
example_test_pytest_esp32_wifi_wlan:
extends:
- .pytest_examples_dir_template
- .rules:test:example_test-esp32
needs:
- build_pytest_examples_esp32
tags: [ esp32, wifi_wlan ]
example_test_pytest_esp32_ethernet_ip101: example_test_pytest_esp32_ethernet_ip101:
extends: extends:
@@ -340,6 +354,7 @@ test_app_test_pytest_esp32s2_usb_host:
junit: $LOG_PATH/*/XUNIT_RESULT.xml junit: $LOG_PATH/*/XUNIT_RESULT.xml
expire_in: 1 week expire_in: 1 week
variables: variables:
GIT_DEPTH: 1
TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw" TEST_FW_PATH: "$CI_PROJECT_DIR/tools/tiny-test-fw"
LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS" LOG_PATH: "$CI_PROJECT_DIR/TEST_LOGS"
ENV_FILE: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/EnvConfig.yml" ENV_FILE: "$CI_PROJECT_DIR/ci-test-runner-configs/$CI_RUNNER_DESCRIPTION/EnvConfig.yml"
@@ -434,7 +449,7 @@ example_test_protocols:
extends: .example_test_esp32_template extends: .example_test_esp32_template
tags: tags:
- ESP32 - ESP32
- Example_WIFI_Protocols - wifi_router
example_test_002: example_test_002:
extends: .example_test_esp32_template extends: .example_test_esp32_template
@@ -446,7 +461,7 @@ example_test_ethernet:
extends: .example_test_esp32_template extends: .example_test_esp32_template
tags: tags:
- ESP32 - ESP32
- Example_Ethernet - ethernet_router
.example_test_003: .example_test_003:
extends: .example_test_esp32_template extends: .example_test_esp32_template
@@ -559,6 +574,7 @@ example_test_ESP32C3_SDSPI:
needs: needs:
- assign_custom_test - assign_custom_test
variables: variables:
GIT_DEPTH: 1
TEST_CASE_PATH: "$CI_PROJECT_DIR/tools/test_apps" TEST_CASE_PATH: "$CI_PROJECT_DIR/tools/test_apps"
CONFIG_FILE_PATH: "${CI_PROJECT_DIR}/tools/test_apps/test_configs" CONFIG_FILE_PATH: "${CI_PROJECT_DIR}/tools/test_apps/test_configs"
@@ -605,7 +621,7 @@ test_app_test_eth:
extends: .test_app_esp32_template extends: .test_app_esp32_template
tags: tags:
- ESP32 - ESP32
- Example_EthKitV1 - ethernet_router
test_app_test_003: test_app_test_003:
extends: .test_app_esp32_template extends: .test_app_esp32_template
@@ -666,6 +682,7 @@ test_app_test_flash_psram_f8r8:
needs: # the assign already needs all the build jobs needs: # the assign already needs all the build jobs
- assign_unit_test - assign_unit_test
variables: variables:
GIT_DEPTH: 1
TEST_CASE_PATH: "$CI_PROJECT_DIR/tools/unit-test-app" TEST_CASE_PATH: "$CI_PROJECT_DIR/tools/unit-test-app"
CONFIG_FILE_PATH: "${CI_PROJECT_DIR}/components/idf_test/unit_test/test_configs" CONFIG_FILE_PATH: "${CI_PROJECT_DIR}/components/idf_test/unit_test/test_configs"

View File

@@ -14,7 +14,9 @@ import re
import subprocess import subprocess
import time import time
import netifaces
import ttfw_idf import ttfw_idf
from common_test_methods import get_env_config, get_my_ip_by_interface
from idf_iperf_test_util import IperfUtility from idf_iperf_test_util import IperfUtility
from tiny_test_fw import TinyFW from tiny_test_fw import TinyFW
@@ -53,14 +55,15 @@ class IperfTestUtilityEth(IperfUtility.IperfTestUtility):
return dut_ip, rssi return dut_ip, rssi
@ttfw_idf.idf_example_test(env_tag='Example_Ethernet') @ttfw_idf.idf_example_test(env_tag='ethernet_router')
def test_ethernet_throughput_basic(env, _): # type: (Any, Any) -> None def test_ethernet_throughput_basic(env, _): # type: (Any, Any) -> None
""" """
steps: | steps: |
1. test TCP tx rx and UDP tx rx throughput 1. test TCP tx rx and UDP tx rx throughput
2. compare with the pre-defined pass standard 2. compare with the pre-defined pass standard
""" """
pc_nic_ip = env.get_pc_nic_info('pc_nic', 'ipv4')['addr'] pc_nic = get_env_config('wifi_router').get('pc_nic', 'eth1')
pc_nic_ip = get_my_ip_by_interface(pc_nic, netifaces.AF_INET)
pc_iperf_log_file = os.path.join(env.log_path, 'pc_iperf_log.md') pc_iperf_log_file = os.path.join(env.log_path, 'pc_iperf_log.md')
# 1. get DUT # 1. get DUT

View File

@@ -1,52 +0,0 @@
# SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
from __future__ import unicode_literals
import re
from typing import Any
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
def test_examples_simple_sniffer(env, _): # type: (Any, Any) -> None
dut = env.get_dut('simple_sniffer', 'examples/network/simple_sniffer', app_config_name='mem')
dut.start_app()
dut.expect('sniffer>')
dut.write('pcap --open -f simple-sniffer')
dut.expect('cmd_pcap: open file successfully')
dut.write('sniffer -i wlan -c 2 -n 10')
dut.expect('cmd_sniffer: 10 packages will be captured')
dut.expect('cmd_sniffer: start WiFi promiscuous ok')
dut.expect('cmd_sniffer: stop promiscuous ok')
dut.write('pcap --summary -f simple-sniffer')
dut.expect('cmd_pcap: Memory is to be parsed')
dut.expect('Pcap packet Head:')
dut.expect('Magic Number: a1b2c3d4')
dut.expect(re.compile(r'Major Version: [0-9]*'))
dut.expect(re.compile(r'Minor Version: [0-9]*'))
dut.expect(re.compile(r'SnapLen: [0-9]*'))
dut.expect(re.compile(r'LinkType: [0-9]*'))
for i in range(0, 10):
dut.expect('Packet ' + str(i) + ':')
dut.expect(re.compile(r'Timestamp \(Seconds\): [0-9]*'))
dut.expect(re.compile(r'Timestamp \(Microseconds\): [0-9]*'))
dut.expect(re.compile(r'Capture Length: [0-9]*'))
dut.expect(re.compile(r'Packet Length: [0-9]*'))
dut.expect(re.compile(r'Frame Type: .*'))
dut.expect(re.compile(r'Frame Subtype: .*'))
dut.expect(re.compile(r'Destination: .*'))
dut.expect(re.compile(r'Source: .*'))
dut.expect('Pcap packet Number: 10')
dut.write('pcap --close -f simple-sniffer')
dut.expect('cmd_pcap: free memory successfully')
dut.expect('cmd_pcap: .pcap file close done')
dut.write('')
dut.expect('sniffer>')
if __name__ == '__main__':
test_examples_simple_sniffer()

View File

@@ -0,0 +1,47 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.wifi_nearby
@pytest.mark.parametrize('config', [
'mem',
], indirect=True)
def test_examples_simple_sniffer(dut: Dut) -> None:
sniffer_num = 10
dut.expect('sniffer>')
dut.write('pcap --open -f simple-sniffer')
dut.expect('cmd_pcap: open file successfully')
dut.write(f'sniffer -i wlan -c 2 -n {sniffer_num}')
dut.expect(f'cmd_sniffer: {sniffer_num} packages will be captured')
dut.expect('cmd_sniffer: start WiFi promiscuous ok')
dut.expect('cmd_sniffer: stop promiscuous ok')
dut.write('pcap --summary -f simple-sniffer')
dut.expect('cmd_pcap: Memory is to be parsed')
dut.expect('Pcap packet Head:')
dut.expect('Magic Number: a1b2c3d4')
dut.expect(r'Major Version: [0-9]+')
dut.expect(r'Minor Version: [0-9]+')
dut.expect(r'SnapLen: [0-9]+')
dut.expect(r'LinkType: [0-9]+')
# Allow "save captured packet failed" once
for i in range(0, sniffer_num - 1):
dut.expect(f'Packet {i}:')
dut.expect(r'Timestamp \(Seconds\): [0-9]+')
dut.expect(r'Timestamp \(Microseconds\): [0-9]+')
dut.expect(r'Capture Length: [0-9]+')
dut.expect(r'Packet Length: [0-9]+')
dut.expect(r'Frame Type:\s+\w+')
dut.expect(r'Frame Subtype:\s+\w+')
dut.expect(r'Destination:\s+\w+')
dut.expect(r'Source:\s+\w+')
dut.expect(r'Pcap packet Number: \d+')
dut.write('pcap --close -f simple-sniffer')
dut.expect('cmd_pcap: free memory successfully')
dut.expect('cmd_pcap: .pcap file close done')
dut.write('')
dut.expect('sniffer>')

View File

@@ -108,7 +108,7 @@ examples/protocols/https_x509_bundle:
examples/protocols/icmp_echo: examples/protocols/icmp_echo:
disable_test: disable_test:
- if: IDF_TARGET != "esp32" - if: IDF_TARGET == "esp32c2"
temporary: true temporary: true
reason: lack of runners reason: lack of runners

View File

@@ -9,7 +9,7 @@ from pytest_embedded import Dut
@pytest.mark.supported_targets @pytest.mark.supported_targets
@pytest.mark.wifi @pytest.mark.generic
def test_examples_cbor(dut: Dut) -> None: def test_examples_cbor(dut: Dut) -> None:
dut.expect(r'example: encoded buffer size \d+') dut.expect(r'example: encoded buffer size \d+')

View File

@@ -39,7 +39,7 @@ class CustomProcess(object):
@pytest.mark.supported_targets @pytest.mark.supported_targets
@pytest.mark.wifi @pytest.mark.wifi_router
def test_examples_esp_local_ctrl(dut: Dut) -> None: def test_examples_esp_local_ctrl(dut: Dut) -> None:
rel_project_path = os.path.join('examples', 'protocols', 'esp_local_ctrl') rel_project_path = os.path.join('examples', 'protocols', 'esp_local_ctrl')

View File

@@ -35,7 +35,7 @@ from pytest_embedded import Dut
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi @pytest.mark.wifi_router
def test_examples_protocol_http_server_advanced(dut: Dut) -> None: def test_examples_protocol_http_server_advanced(dut: Dut) -> None:
# Get binary file # Get binary file

View File

@@ -72,7 +72,7 @@ def test_captive_page(ip: str, port: str, uri: str) -> bool:
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi_bt @pytest.mark.wifi_wlan
@pytest.mark.xfail(reason='Runner unable to connect to target over WiFi', run=False) @pytest.mark.xfail(reason='Runner unable to connect to target over WiFi', run=False)
def test_example_captive_portal(dut: Dut) -> None: def test_example_captive_portal(dut: Dut) -> None:

View File

@@ -30,7 +30,7 @@ from pytest_embedded import Dut
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi @pytest.mark.wifi_router
def test_examples_protocol_http_server_persistence(dut: Dut) -> None: def test_examples_protocol_http_server_persistence(dut: Dut) -> None:
# Get binary file # Get binary file

View File

@@ -62,7 +62,7 @@ class http_client_thread(threading.Thread):
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi @pytest.mark.wifi_router
def test_examples_protocol_http_server_simple(dut: Dut) -> None: def test_examples_protocol_http_server_simple(dut: Dut) -> None:
# Get binary file # Get binary file
@@ -130,7 +130,7 @@ def test_examples_protocol_http_server_simple(dut: Dut) -> None:
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi @pytest.mark.wifi_router
def test_examples_protocol_http_server_lru_purge_enable(dut: Dut) -> None: def test_examples_protocol_http_server_lru_purge_enable(dut: Dut) -> None:
# Get binary file # Get binary file

View File

@@ -51,7 +51,7 @@ class WsClient:
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi @pytest.mark.wifi_router
def test_examples_protocol_http_ws_echo_server(dut: Dut) -> None: def test_examples_protocol_http_ws_echo_server(dut: Dut) -> None:
# Get binary file # Get binary file
binary_file = os.path.join(dut.app.binary_path, 'ws_echo_server.bin') binary_file = os.path.join(dut.app.binary_path, 'ws_echo_server.bin')

View File

@@ -10,19 +10,11 @@ from typing import Callable
import pexpect import pexpect
import pytest import pytest
from common_test_methods import get_my_ip4_by_dest_ip
from pytest_embedded import Dut from pytest_embedded import Dut
from RangeHTTPServer import RangeRequestHandler from RangeHTTPServer import RangeRequestHandler
def get_my_ip() -> str:
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s1.connect(('8.8.8.8', 80))
my_ip = ''
my_ip = s1.getsockname()[0]
s1.close()
return my_ip
def get_server_status(host_ip: str, port: int) -> bool: def get_server_status(host_ip: str, port: int) -> bool:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_status = sock.connect_ex((host_ip, port)) server_status = sock.connect_ex((host_ip, port))
@@ -86,7 +78,15 @@ def test_examples_protocol_https_request_cli_session_tickets(dut: Dut) -> None:
bin_size = os.path.getsize(binary_file) bin_size = os.path.getsize(binary_file)
logging.info('https_request_bin_size : {}KB'.format(bin_size // 1024)) logging.info('https_request_bin_size : {}KB'.format(bin_size // 1024))
# start test # start test
host_ip = get_my_ip() dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)', timeout=60)[1].decode()
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
# start https server
host_ip = get_my_ip4_by_dest_ip(ip_address)
server_port = 8070 server_port = 8070
server_file = os.path.join(os.path.dirname(__file__), 'main', 'local_server_cert.pem') server_file = os.path.join(os.path.dirname(__file__), 'main', 'local_server_cert.pem')
key_file = os.path.join(os.path.dirname(__file__), 'main', 'local_server_key.pem') key_file = os.path.join(os.path.dirname(__file__), 'main', 'local_server_key.pem')
@@ -96,17 +96,9 @@ def test_examples_protocol_https_request_cli_session_tickets(dut: Dut) -> None:
thread1.start() thread1.start()
logging.info('The server started on {}:{}'.format(host_ip, server_port)) logging.info('The server started on {}:{}'.format(host_ip, server_port))
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: (\d+\.\d+\.\d+\.\d+)', timeout=60)[2].decode()
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Start https_request example', timeout=30) dut.expect('Start https_request example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port))) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port)))
dut.write('https://' + host_ip + ':' + str(server_port)) dut.write('https://' + host_ip + ':' + str(server_port))
logging.info("Testing for \"https_request using saved session\"") logging.info("Testing for \"https_request using saved session\"")

View File

@@ -93,7 +93,7 @@ success_response = '<h1>Hello Secure World!</h1>'
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi @pytest.mark.wifi_router
def test_examples_protocol_https_server_simple(dut: Dut) -> None: def test_examples_protocol_https_server_simple(dut: Dut) -> None:
""" """
steps: | steps: |
@@ -168,7 +168,7 @@ def test_examples_protocol_https_server_simple(dut: Dut) -> None:
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi @pytest.mark.wifi_router
@pytest.mark.parametrize('config', ['dynamic_buffer',], indirect=True) @pytest.mark.parametrize('config', ['dynamic_buffer',], indirect=True)
def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None: def test_examples_protocol_https_server_simple_dynamic_buffers(dut: Dut) -> None:
# Test with mbedTLS dynamic buffer feature # Test with mbedTLS dynamic buffer feature

View File

@@ -109,7 +109,7 @@ def test_multiple_client_keep_alive_and_async_response(ip, port, ca_file): # ty
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi @pytest.mark.wifi_router
def test_examples_protocol_https_wss_server(dut: Dut) -> None: def test_examples_protocol_https_wss_server(dut: Dut) -> None:
# Get binary file # Get binary file

View File

@@ -11,7 +11,7 @@ from pytest_embedded import Dut
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi @pytest.mark.wifi_router
def test_examples_protocol_https_x509_bundle(dut: Dut) -> None: def test_examples_protocol_https_x509_bundle(dut: Dut) -> None:
""" """
steps: | steps: |
@@ -33,7 +33,7 @@ def test_examples_protocol_https_x509_bundle(dut: Dut) -> None:
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.wifi @pytest.mark.wifi_router
@pytest.mark.parametrize('config', ['ssldyn',], indirect=True) @pytest.mark.parametrize('config', ['ssldyn',], indirect=True)
def test_examples_protocol_https_x509_bundle_dynamic_buffer(dut: Dut) -> None: def test_examples_protocol_https_x509_bundle_dynamic_buffer(dut: Dut) -> None:
# test mbedtls dynamic resource # test mbedtls dynamic resource

View File

@@ -1,33 +0,0 @@
from __future__ import unicode_literals
import os
import re
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
def test_examples_icmp_echo(env, extra_data):
dut = env.get_dut('icmp_echo', 'examples/protocols/icmp_echo')
dut.start_app()
dut.expect('example_connect: Connected to')
dut.expect('esp>')
ping_dest = os.getenv('EXAMPLE_ICMP_SERVER', 'www.espressif.com')
dut.write('ping {}'.format(ping_dest))
ip_re = r'\.'.join((r'\d{1,3}',) * 4)
ip = dut.expect(re.compile(r'64 bytes from ({}) icmp_seq=1 ttl=\d+ time=\d+ ms'.format(ip_re)))[0]
# expect at least one more (there could be lost packets)
dut.expect(re.compile(r'64 bytes from {} icmp_seq=[2-5] ttl=\d+ time='.format(ip)))
dut.expect(re.compile(r'5 packets transmitted, [2-5] received, \d{1,3}% packet loss'))
dut.write('')
dut.expect('esp>')
if __name__ == '__main__':
test_examples_icmp_echo()

View File

@@ -199,8 +199,6 @@ void app_main(void)
ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default()); ESP_ERROR_CHECK(esp_event_loop_create_default());
/* wait for active network connection */
ESP_ERROR_CHECK(example_connect());
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
// install console REPL environment // install console REPL environment
@@ -215,6 +213,8 @@ void app_main(void)
ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&usbjtag_config, &repl_config, &repl)); ESP_ERROR_CHECK(esp_console_new_repl_usb_serial_jtag(&usbjtag_config, &repl_config, &repl));
#endif #endif
/* register wifi connect commands */
register_wifi_connect_commands();
/* register command `ping` */ /* register command `ping` */
register_ping(); register_ping();
/* register command `quit` */ /* register command `quit` */

View File

@@ -0,0 +1,36 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import os
import pytest
from common_test_methods import get_env_config
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.esp32c3
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.wifi_nearby
def test_protocols_icmp_echo(dut: Dut) -> None:
# get env config
env_config = get_env_config('wifi_nearby')
ap_ssid = env_config['ap_ssid']
ap_password = env_config['ap_password']
ap_channel = env_config.get('ap_channel', 0)
dut.expect('esp>')
dut.write(f'wifi_connect {ap_ssid} {ap_password} -n {ap_channel}')
dut.expect('Got IPv4 event:', timeout=30)
ping_dest = os.getenv('EXAMPLE_ICMP_SERVER', 'ci.espressif.cn')
dut.write('ping {} -c 5'.format(ping_dest))
# expect at least two packets (there could be lost packets)
ip = dut.expect(r'64 bytes from (\d+\.\d+\.\d+\.\d+) icmp_seq=\d ttl=\d+ time=\d+ ms')[1].decode()
dut.expect(fr'64 bytes from {ip} icmp_seq=[2-5] ttl=\d+ time=')
dut.expect(r'5 packets transmitted, [2-5] received, \d{1,3}% packet loss')
dut.write('')
dut.expect('esp>')

View File

@@ -7,19 +7,12 @@ import time
from threading import Thread from threading import Thread
import ttfw_idf import ttfw_idf
from common_test_methods import get_my_ip4_by_dest_ip
from tiny_test_fw import DUT from tiny_test_fw import DUT
msgid = -1 msgid = -1
def get_my_ip():
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s1.connect(('8.8.8.8', 80))
my_ip = s1.getsockname()[0]
s1.close()
return my_ip
def mqqt_server_sketch(my_ip, port): def mqqt_server_sketch(my_ip, port):
global msgid global msgid
print('Starting the server on {}'.format(my_ip)) print('Starting the server on {}'.format(my_ip))
@@ -68,19 +61,20 @@ def test_examples_protocol_mqtt_qos1(env, extra_data):
binary_file = os.path.join(dut1.app.binary_path, 'mqtt_tcp.bin') binary_file = os.path.join(dut1.app.binary_path, 'mqtt_tcp.bin')
bin_size = os.path.getsize(binary_file) bin_size = os.path.getsize(binary_file)
ttfw_idf.log_performance('mqtt_tcp_bin_size', '{}KB'.format(bin_size // 1024)) ttfw_idf.log_performance('mqtt_tcp_bin_size', '{}KB'.format(bin_size // 1024))
# 1. start mqtt broker sketch # 1. start the dut test and wait till client gets IP address
host_ip = get_my_ip()
thread1 = Thread(target=mqqt_server_sketch, args=(host_ip,1883))
thread1.start()
# 2. start the dut test and wait till client gets IP address
dut1.start_app() dut1.start_app()
# waiting for getting the IP address # waiting for getting the IP address
try: try:
ip_address = dut1.expect(re.compile(r'IPv4 address: ([^,]+),'), timeout=30) ip_address = dut1.expect(re.compile(r'IPv4 address: ([^,]+),'), timeout=30)[0]
print('Connected to AP/Ethernet with IP: {}'.format(ip_address)) print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except DUT.ExpectTimeout: except DUT.ExpectTimeout:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet') raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# 2. start mqtt broker sketch
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = Thread(target=mqqt_server_sketch, args=(host_ip,1883))
thread1.start()
print('writing to device: {}'.format('mqtt://' + host_ip + '\n')) print('writing to device: {}'.format('mqtt://' + host_ip + '\n'))
dut1.write('mqtt://' + host_ip + '\n') dut1.write('mqtt://' + host_ip + '\n')
thread1.join() thread1.join()

View File

@@ -1,51 +0,0 @@
from __future__ import unicode_literals
import datetime
import re
import ttfw_idf
from tiny_test_fw import Utility
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols')
def test_examples_sntp(env, extra_data):
dut = env.get_dut('sntp', 'examples/protocols/sntp')
dut.start_app()
dut.expect_all('Time is not set yet. Connecting to WiFi and getting time over NTP.',
'Initializing SNTP',
re.compile(r'Waiting for system time to be set... \(\d+/\d+\)'),
'Notification of a time synchronization event',
timeout=60)
TIME_FORMAT = '%a %b %d %H:%M:%S %Y'
TIME_FORMAT_REGEX = r'\w+\s+\w+\s+\d{1,2}\s+\d{2}:\d{2}:\d{2} \d{4}'
TIME_DIFF = datetime.timedelta(seconds=10 + 2) # cpu spends 10 seconds in deep sleep
NY_time = None
SH_time = None
def check_time(prev_NY_time, prev_SH_time):
NY_str = dut.expect(re.compile(r'The current date/time in New York is: ({})'.format(TIME_FORMAT_REGEX)))[0]
SH_str = dut.expect(re.compile(r'The current date/time in Shanghai is: ({})'.format(TIME_FORMAT_REGEX)))[0]
Utility.console_log('New York: "{}"'.format(NY_str))
Utility.console_log('Shanghai: "{}"'.format(SH_str))
dut.expect('Entering deep sleep for 10 seconds')
Utility.console_log('Sleeping...')
new_NY_time = datetime.datetime.strptime(NY_str, TIME_FORMAT)
new_SH_time = datetime.datetime.strptime(SH_str, TIME_FORMAT)
# The initial time is not checked because datetime has problems with timezones
assert prev_NY_time is None or new_NY_time - prev_NY_time < TIME_DIFF
assert prev_SH_time is None or new_SH_time - prev_SH_time < TIME_DIFF
return (new_NY_time, new_SH_time)
NY_time, SH_time = check_time(NY_time, SH_time)
for i in range(2, 4):
dut.expect('example: Boot count: {}'.format(i), timeout=30)
NY_time, SH_time = check_time(NY_time, SH_time)
if __name__ == '__main__':
test_examples_sntp()

View File

@@ -0,0 +1,55 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import datetime
import logging
from typing import Any, Tuple
import pytest
from common_test_methods import get_env_config
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.wifi_nearby
def test_get_time_from_sntp_server(dut: Dut) -> None:
dut.expect('Time is not set yet. Connecting to WiFi and getting time over NTP.')
if dut.app.sdkconfig.get('EXAMPLE_WIFI_SSID_PWD_FROM_STDIN') is True:
# get env config
env_config = get_env_config('wifi_nearby')
ap_ssid = env_config['ap_ssid']
ap_password = env_config['ap_password']
dut.expect('Please input ssid password:')
dut.write(' '.join([ap_ssid, ap_password]))
dut.expect('IPv4 address:')
dut.expect('Initializing SNTP')
dut.expect(r'Waiting for system time to be set... \(\d+/\d+\)')
dut.expect('Notification of a time synchronization event')
TIME_FORMAT = '%a %b %d %H:%M:%S %Y'
TIME_FORMAT_REGEX = r'\w+\s+\w+\s+\d{1,2}\s+\d{2}:\d{2}:\d{2} \d{4}'
TIME_DIFF = datetime.timedelta(seconds=10 + 2) # cpu spends 10 seconds in deep sleep
NY_time = None
SH_time = None
def check_time(prev_NY_time: Any, prev_SH_time: Any) -> Tuple[Any, Any]:
NY_str = dut.expect(r'The current date/time in New York is: ({})'.format(TIME_FORMAT_REGEX))[1].decode()
SH_str = dut.expect(r'The current date/time in Shanghai is: ({})'.format(TIME_FORMAT_REGEX))[1].decode()
logging.info('New York: "{}"'.format(NY_str))
logging.info('Shanghai: "{}"'.format(SH_str))
dut.expect('Entering deep sleep for 10 seconds')
logging.info('Sleeping...')
new_NY_time = datetime.datetime.strptime(NY_str, TIME_FORMAT)
new_SH_time = datetime.datetime.strptime(SH_str, TIME_FORMAT)
# The initial time is not checked because datetime has problems with timezones
assert not prev_NY_time or new_NY_time - prev_NY_time < TIME_DIFF
assert not prev_SH_time or new_SH_time - prev_SH_time < TIME_DIFF
return (new_NY_time, new_SH_time)
NY_time, SH_time = check_time(NY_time, SH_time)
for i in range(2, 4):
dut.expect('example: Boot count: {}'.format(i), timeout=30)
NY_time, SH_time = check_time(NY_time, SH_time)

View File

@@ -1,2 +1,3 @@
CONFIG_SNTP_TIME_SERVER="time.windows.com" CONFIG_SNTP_TIME_SERVER="time.windows.com"
CONFIG_LWIP_SNTP_MAX_SERVERS=2 CONFIG_LWIP_SNTP_MAX_SERVERS=2
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y

View File

@@ -17,18 +17,13 @@ from threading import Event, Thread
import netifaces import netifaces
import ttfw_idf import ttfw_idf
from common_test_methods import get_env_config, get_my_interface_by_dest_ip, get_my_ip_by_interface
# ----------- Config ---------- # ----------- Config ----------
PORT = 3333 PORT = 3333
INTERFACE = 'eth0'
# ------------------------------- # -------------------------------
def get_my_ip(type):
for i in netifaces.ifaddresses(INTERFACE)[type]:
return i['addr'].replace('%{}'.format(INTERFACE), '')
class TcpServer: class TcpServer:
def __init__(self, port, family_addr, persist=False): def __init__(self, port, family_addr, persist=False):
@@ -85,7 +80,7 @@ class TcpServer:
break break
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols') @ttfw_idf.idf_example_test(env_tag='wifi_router')
def test_examples_protocol_socket_tcpclient(env, extra_data): def test_examples_protocol_socket_tcpclient(env, extra_data):
""" """
steps: steps:
@@ -93,6 +88,11 @@ def test_examples_protocol_socket_tcpclient(env, extra_data):
2. have the board connect to the server 2. have the board connect to the server
3. send and receive data 3. send and receive data
""" """
# get env config
env_config = get_env_config('wifi_router')
ap_ssid = env_config['ap_ssid']
ap_password = env_config['ap_password']
dut1 = env.get_dut('tcp_client', 'examples/protocols/sockets/tcp_client', dut_class=ttfw_idf.ESP32DUT) dut1 = env.get_dut('tcp_client', 'examples/protocols/sockets/tcp_client', dut_class=ttfw_idf.ESP32DUT)
# check and log bin size # check and log bin size
binary_file = os.path.join(dut1.app.binary_path, 'tcp_client.bin') binary_file = os.path.join(dut1.app.binary_path, 'tcp_client.bin')
@@ -101,21 +101,24 @@ def test_examples_protocol_socket_tcpclient(env, extra_data):
# start test # start test
dut1.start_app() dut1.start_app()
dut1.expect('Please input ssid password:')
dut1.write(' '.join([ap_ssid, ap_password]))
ipv4 = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)[0] ipv4 = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)[0]
ipv6_r = r':'.join((r'[0-9a-fA-F]{4}',) * 8) # expect all 8 octets from IPv6 (assumes it's printed in the long form) ipv6_r = r':'.join((r'[0-9a-fA-F]{4}',) * 8) # expect all 8 octets from IPv6 (assumes it's printed in the long form)
ipv6 = dut1.expect(re.compile(r' IPv6 address: ({})'.format(ipv6_r)), timeout=30)[0] ipv6 = dut1.expect(re.compile(r' IPv6 address: ({})'.format(ipv6_r)), timeout=30)[0]
print('Connected with IPv4={} and IPv6={}'.format(ipv4, ipv6)) print('Connected with IPv4={} and IPv6={}'.format(ipv4, ipv6))
my_interface = get_my_interface_by_dest_ip(ipv4)
# test IPv4 # test IPv4
with TcpServer(PORT, socket.AF_INET): with TcpServer(PORT, socket.AF_INET):
server_ip = get_my_ip(netifaces.AF_INET) server_ip = get_my_ip_by_interface(my_interface, netifaces.AF_INET)
print('Connect tcp client to server IP={}'.format(server_ip)) print('Connect tcp client to server IP={}'.format(server_ip))
dut1.write(server_ip) dut1.write(server_ip)
dut1.expect(re.compile(r'OK: Message from ESP32')) dut1.expect(re.compile(r'OK: Message from ESP32'))
# test IPv6 # test IPv6
with TcpServer(PORT, socket.AF_INET6): with TcpServer(PORT, socket.AF_INET6):
server_ip = get_my_ip(netifaces.AF_INET6) server_ip = get_my_ip_by_interface(my_interface, netifaces.AF_INET6)
print('Connect tcp client to server IP={}'.format(server_ip)) print('Connect tcp client to server IP={}'.format(server_ip))
dut1.write(server_ip) dut1.write(server_ip)
dut1.expect(re.compile(r'OK: Message from ESP32')) dut1.expect(re.compile(r'OK: Message from ESP32'))

View File

@@ -1 +1,2 @@
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN=y CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN=y

View File

@@ -14,10 +14,10 @@ import socket
import sys import sys
import ttfw_idf import ttfw_idf
from common_test_methods import get_env_config, get_my_interface_by_dest_ip
# ----------- Config ---------- # ----------- Config ----------
PORT = 3333 PORT = 3333
INTERFACE = 'eth0'
# ------------------------------- # -------------------------------
@@ -46,7 +46,7 @@ def tcp_client(address, payload):
return data.decode() return data.decode()
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols') @ttfw_idf.idf_example_test(env_tag='wifi_router')
def test_examples_protocol_socket_tcpserver(env, extra_data): def test_examples_protocol_socket_tcpserver(env, extra_data):
MESSAGE = 'Data to ESP' MESSAGE = 'Data to ESP'
""" """
@@ -55,6 +55,11 @@ def test_examples_protocol_socket_tcpserver(env, extra_data):
2. have the board connect to the server 2. have the board connect to the server
3. send and receive data 3. send and receive data
""" """
# get env config
env_config = get_env_config('wifi_router')
ap_ssid = env_config['ap_ssid']
ap_password = env_config['ap_password']
dut1 = env.get_dut('tcp_client', 'examples/protocols/sockets/tcp_server', dut_class=ttfw_idf.ESP32DUT) dut1 = env.get_dut('tcp_client', 'examples/protocols/sockets/tcp_server', dut_class=ttfw_idf.ESP32DUT)
# check and log bin size # check and log bin size
binary_file = os.path.join(dut1.app.binary_path, 'tcp_server.bin') binary_file = os.path.join(dut1.app.binary_path, 'tcp_server.bin')
@@ -63,19 +68,22 @@ def test_examples_protocol_socket_tcpserver(env, extra_data):
# start test # start test
dut1.start_app() dut1.start_app()
dut1.expect('Please input ssid password:')
dut1.write(' '.join([ap_ssid, ap_password]))
ipv4 = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)[0] ipv4 = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)[0]
ipv6_r = r':'.join((r'[0-9a-fA-F]{4}',) * 8) # expect all 8 octets from IPv6 (assumes it's printed in the long form) ipv6_r = r':'.join((r'[0-9a-fA-F]{4}',) * 8) # expect all 8 octets from IPv6 (assumes it's printed in the long form)
ipv6 = dut1.expect(re.compile(r' IPv6 address: ({})'.format(ipv6_r)), timeout=30)[0] ipv6 = dut1.expect(re.compile(r' IPv6 address: ({})'.format(ipv6_r)), timeout=30)[0]
print('Connected with IPv4={} and IPv6={}'.format(ipv4, ipv6)) print('Connected with IPv4={} and IPv6={}'.format(ipv4, ipv6))
interface = get_my_interface_by_dest_ip(ipv4)
# test IPv4 # test IPv4
received = tcp_client(ipv4, MESSAGE) received = tcp_client(ipv4, MESSAGE)
if not received == MESSAGE: if not received == MESSAGE:
raise raise
dut1.expect(MESSAGE) dut1.expect(MESSAGE)
# test IPv6 # test IPv6
received = tcp_client('{}%{}'.format(ipv6, INTERFACE), MESSAGE) received = tcp_client('{}%{}'.format(ipv6, interface), MESSAGE)
if not received == MESSAGE: if not received == MESSAGE:
raise raise
dut1.expect(MESSAGE) dut1.expect(MESSAGE)

View File

@@ -1,2 +1,3 @@
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_IPV4=y CONFIG_EXAMPLE_IPV4=y
CONFIG_EXAMPLE_IPV6=y CONFIG_EXAMPLE_IPV6=y

View File

@@ -1,3 +1,4 @@
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_IPV4=y CONFIG_EXAMPLE_IPV4=y
CONFIG_EXAMPLE_IPV6=n CONFIG_EXAMPLE_IPV6=n
CONFIG_EXAMPLE_CONNECT_IPV6=n CONFIG_EXAMPLE_CONNECT_IPV6=n

View File

@@ -17,18 +17,13 @@ from threading import Event, Thread
import netifaces import netifaces
import ttfw_idf import ttfw_idf
from common_test_methods import get_env_config, get_my_interface_by_dest_ip, get_my_ip_by_interface
# ----------- Config ---------- # ----------- Config ----------
PORT = 3333 PORT = 3333
INTERFACE = 'eth0'
# ------------------------------- # -------------------------------
def get_my_ip(type):
for i in netifaces.ifaddresses(INTERFACE)[type]:
return i['addr'].replace('%{}'.format(INTERFACE), '')
class UdpServer: class UdpServer:
def __init__(self, port, family_addr, persist=False): def __init__(self, port, family_addr, persist=False):
@@ -78,7 +73,7 @@ class UdpServer:
break break
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols') @ttfw_idf.idf_example_test(env_tag='wifi_router')
def test_examples_protocol_socket_udpclient(env, extra_data): def test_examples_protocol_socket_udpclient(env, extra_data):
""" """
steps: steps:
@@ -86,6 +81,11 @@ def test_examples_protocol_socket_udpclient(env, extra_data):
2. have the board connect to the server 2. have the board connect to the server
3. send and receive data 3. send and receive data
""" """
# get env config
env_config = get_env_config('wifi_router')
ap_ssid = env_config['ap_ssid']
ap_password = env_config['ap_password']
dut1 = env.get_dut('udp_client', 'examples/protocols/sockets/udp_client', dut_class=ttfw_idf.ESP32DUT) dut1 = env.get_dut('udp_client', 'examples/protocols/sockets/udp_client', dut_class=ttfw_idf.ESP32DUT)
# check and log bin size # check and log bin size
binary_file = os.path.join(dut1.app.binary_path, 'udp_client.bin') binary_file = os.path.join(dut1.app.binary_path, 'udp_client.bin')
@@ -94,21 +94,24 @@ def test_examples_protocol_socket_udpclient(env, extra_data):
# start test # start test
dut1.start_app() dut1.start_app()
dut1.expect('Please input ssid password:')
dut1.write(' '.join([ap_ssid, ap_password]))
ipv4 = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)[0] ipv4 = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)[0]
ipv6_r = r':'.join((r'[0-9a-fA-F]{4}',) * 8) # expect all 8 octets from IPv6 (assumes it's printed in the long form) ipv6_r = r':'.join((r'[0-9a-fA-F]{4}',) * 8) # expect all 8 octets from IPv6 (assumes it's printed in the long form)
ipv6 = dut1.expect(re.compile(r' IPv6 address: ({})'.format(ipv6_r)), timeout=30)[0] ipv6 = dut1.expect(re.compile(r' IPv6 address: ({})'.format(ipv6_r)), timeout=30)[0]
print('Connected with IPv4={} and IPv6={}'.format(ipv4, ipv6)) print('Connected with IPv4={} and IPv6={}'.format(ipv4, ipv6))
my_interface = get_my_interface_by_dest_ip(ipv4)
# test IPv4 # test IPv4
with UdpServer(PORT, socket.AF_INET): with UdpServer(PORT, socket.AF_INET):
server_ip = get_my_ip(netifaces.AF_INET) server_ip = get_my_ip_by_interface(my_interface, netifaces.AF_INET)
print('Connect udp client to server IP={}'.format(server_ip)) print('Connect udp client to server IP={}'.format(server_ip))
dut1.write(server_ip) dut1.write(server_ip)
dut1.expect(re.compile(r'OK: Message from ESP32')) dut1.expect(re.compile(r'OK: Message from ESP32'))
# test IPv6 # test IPv6
with UdpServer(PORT, socket.AF_INET6): with UdpServer(PORT, socket.AF_INET6):
server_ip = get_my_ip(netifaces.AF_INET6) server_ip = get_my_ip_by_interface(my_interface, netifaces.AF_INET6)
print('Connect udp client to server IP={}'.format(server_ip)) print('Connect udp client to server IP={}'.format(server_ip))
dut1.write(server_ip) dut1.write(server_ip)
dut1.expect(re.compile(r'OK: Message from ESP32')) dut1.expect(re.compile(r'OK: Message from ESP32'))

View File

@@ -1 +1,2 @@
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN=y CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN=y

View File

@@ -14,10 +14,10 @@ import socket
import sys import sys
import ttfw_idf import ttfw_idf
from common_test_methods import get_env_config, get_my_interface_by_dest_ip
# ----------- Config ---------- # ----------- Config ----------
PORT = 3333 PORT = 3333
INTERFACE = 'eth0'
# ------------------------------- # -------------------------------
@@ -49,7 +49,7 @@ def udp_client(address, payload):
return reply.decode() return reply.decode()
@ttfw_idf.idf_example_test(env_tag='Example_WIFI_Protocols') @ttfw_idf.idf_example_test(env_tag='wifi_router')
def test_examples_protocol_socket_udpserver(env, extra_data): def test_examples_protocol_socket_udpserver(env, extra_data):
MESSAGE = 'Data to ESP' MESSAGE = 'Data to ESP'
MAX_RETRIES = 3 MAX_RETRIES = 3
@@ -59,6 +59,11 @@ def test_examples_protocol_socket_udpserver(env, extra_data):
2. have the board connect to the server 2. have the board connect to the server
3. send and receive data 3. send and receive data
""" """
# get env config
env_config = get_env_config('wifi_router')
ap_ssid = env_config['ap_ssid']
ap_password = env_config['ap_password']
dut1 = env.get_dut('udp_server', 'examples/protocols/sockets/udp_server', dut_class=ttfw_idf.ESP32DUT) dut1 = env.get_dut('udp_server', 'examples/protocols/sockets/udp_server', dut_class=ttfw_idf.ESP32DUT)
# check and log bin size # check and log bin size
binary_file = os.path.join(dut1.app.binary_path, 'udp_server.bin') binary_file = os.path.join(dut1.app.binary_path, 'udp_server.bin')
@@ -67,6 +72,8 @@ def test_examples_protocol_socket_udpserver(env, extra_data):
# start test # start test
dut1.start_app() dut1.start_app()
dut1.expect('Please input ssid password:')
dut1.write(' '.join([ap_ssid, ap_password]))
ipv4 = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)[0] ipv4 = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)[0]
ipv6_r = r':'.join((r'[0-9a-fA-F]{4}',) * 8) # expect all 8 octets from IPv6 (assumes it's printed in the long form) ipv6_r = r':'.join((r'[0-9a-fA-F]{4}',) * 8) # expect all 8 octets from IPv6 (assumes it's printed in the long form)
@@ -74,6 +81,7 @@ def test_examples_protocol_socket_udpserver(env, extra_data):
print('Connected with IPv4={} and IPv6={}'.format(ipv4, ipv6)) print('Connected with IPv4={} and IPv6={}'.format(ipv4, ipv6))
dut1.expect(re.compile(r'Waiting for data'), timeout=10) dut1.expect(re.compile(r'Waiting for data'), timeout=10)
interface = get_my_interface_by_dest_ip(ipv4)
# test IPv4 # test IPv4
for _ in range(MAX_RETRIES): for _ in range(MAX_RETRIES):
print('Testing UDP on IPv4...') print('Testing UDP on IPv4...')
@@ -88,7 +96,7 @@ def test_examples_protocol_socket_udpserver(env, extra_data):
# test IPv6 # test IPv6
for _ in range(MAX_RETRIES): for _ in range(MAX_RETRIES):
print('Testing UDP on IPv6...') print('Testing UDP on IPv6...')
received = udp_client('{}%{}'.format(ipv6, INTERFACE), MESSAGE) received = udp_client('{}%{}'.format(ipv6, interface), MESSAGE)
if received == MESSAGE: if received == MESSAGE:
print('OK') print('OK')
break break

View File

@@ -1,2 +1,3 @@
CONFIG_EXAMPLE_WIFI_SSID_PWD_FROM_STDIN=y
CONFIG_EXAMPLE_IPV4=y CONFIG_EXAMPLE_IPV4=y
CONFIG_EXAMPLE_IPV6=y CONFIG_EXAMPLE_IPV6=y

View File

@@ -1,5 +1,6 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0 # SPDX-License-Identifier: Unlicense OR CC0-1.0
from ast import Try
import http.server import http.server
import multiprocessing import multiprocessing
import os import os
@@ -12,6 +13,7 @@ from typing import Callable
import pexpect import pexpect
import pytest import pytest
from common_test_methods import get_my_ip4_by_dest_ip
from pytest_embedded import Dut from pytest_embedded import Dut
from RangeHTTPServer import RangeRequestHandler from RangeHTTPServer import RangeRequestHandler
@@ -19,15 +21,6 @@ server_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test_cer
key_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test_certs/server_key.pem') key_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test_certs/server_key.pem')
def get_my_ip() -> str:
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s1.connect(('8.8.8.8', 80))
my_ip = ''
my_ip = s1.getsockname()[0]
s1.close()
return my_ip
def https_request_handler() -> Callable[...,http.server.BaseHTTPRequestHandler]: def https_request_handler() -> Callable[...,http.server.BaseHTTPRequestHandler]:
""" """
Returns a request handler class that handles broken pipe exception Returns a request handler class that handles broken pipe exception
@@ -104,86 +97,86 @@ def start_redirect_server(ota_image_dir: str, server_ip: str, server_port: int,
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_advanced_https_ota_example(dut: Dut) -> None: def test_examples_protocol_advanced_https_ota_example(dut: Dut) -> None:
""" """
This is a positive test case, which downloads complete binary file multiple number of times. This is a positive test case, which downloads complete binary file multiple number of times.
Number of iterations can be specified in variable iterations. Number of iterations can be specified in variable iterations.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
try: # Number of iterations to validate OTA
# Number of iterations to validate OTA iterations = 3
iterations = 3 server_port = 8001
server_port = 8001 bin_name = 'advanced_https_ota.bin'
bin_name = 'advanced_https_ota.bin' # start test
# start test for _ in range(iterations):
host_ip = get_my_ip() dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting Advanced OTA example', timeout=30)
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port)) thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True thread1.daemon = True
thread1.start() thread1.start()
for i in range(iterations): try:
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)
finally: finally:
thread1.terminate() thread1.terminate()
@pytest.mark.esp32 @pytest.mark.esp32
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_advanced_https_ota_example_truncated_bin(dut: Dut) -> None: def test_examples_protocol_advanced_https_ota_example_truncated_bin(dut: Dut) -> None:
""" """
Working of OTA if binary file is truncated is validated in this test case. Working of OTA if binary file is truncated is validated in this test case.
Application should return with error message in this case. Application should return with error message in this case.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Generate truncated binary file 2. Generate truncated binary file
3. Fetch OTA image over HTTPS 3. Fetch OTA image over HTTPS
4. Check working of code if bin is truncated 4. Check working of code if bin is truncated
""" """
server_port = 8001
# Original binary file generated after compilation
bin_name = 'advanced_https_ota.bin'
# Truncated binary file to be generated from original binary file
truncated_bin_name = 'truncated.bin'
# Size of truncated file to be grnerated. This value can range from 288 bytes (Image header size) to size of original binary file
# truncated_bin_size is set to 64000 to reduce consumed by the test case
truncated_bin_size = 64000
binary_file = os.path.join(dut.app.binary_path, bin_name)
with open(binary_file, 'rb+') as f:
with open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+') as fo:
fo.write(f.read(truncated_bin_size))
binary_file = os.path.join(dut.app.binary_path, truncated_bin_name)
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
server_port = 8001 ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
# Original binary file generated after compilation print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
bin_name = 'advanced_https_ota.bin' except pexpect.exceptions.TIMEOUT:
# Truncated binary file to be generated from original binary file raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
truncated_bin_name = 'truncated.bin' dut.expect('Starting Advanced OTA example', timeout=30)
# Size of truncated file to be grnerated. This value can range from 288 bytes (Image header size) to size of original binary file
# truncated_bin_size is set to 64000 to reduce consumed by the test case
truncated_bin_size = 64000
binary_file = os.path.join(dut.app.binary_path, bin_name)
with open(binary_file, 'rb+') as f:
with open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+') as fo:
fo.write(f.read(truncated_bin_size))
binary_file = os.path.join(dut.app.binary_path, truncated_bin_name) # Start server
# start test host_ip = get_my_ip4_by_dest_ip(ip_address)
host_ip = get_my_ip() thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port)) thread1.daemon = True
thread1.daemon = True thread1.start()
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting Advanced OTA example', timeout=30)
try:
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name)
dut.expect('Image validation failed, image is corrupted', timeout=30) dut.expect('Image validation failed, image is corrupted', timeout=30)
@@ -199,46 +192,46 @@ def test_examples_protocol_advanced_https_ota_example_truncated_bin(dut: Dut) ->
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_advanced_https_ota_example_truncated_header(dut: Dut) -> None: def test_examples_protocol_advanced_https_ota_example_truncated_header(dut: Dut) -> None:
""" """
Working of OTA if headers of binary file are truncated is vaildated in this test case. Working of OTA if headers of binary file are truncated is vaildated in this test case.
Application should return with error message in this case. Application should return with error message in this case.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Generate binary file with truncated headers 2. Generate binary file with truncated headers
3. Fetch OTA image over HTTPS 3. Fetch OTA image over HTTPS
4. Check working of code if headers are not sent completely 4. Check working of code if headers are not sent completely
""" """
server_port = 8001
# Original binary file generated after compilation
bin_name = 'advanced_https_ota.bin'
# Truncated binary file to be generated from original binary file
truncated_bin_name = 'truncated_header.bin'
# Size of truncated file to be generated. This value should be less than 288 bytes (Image header size)
truncated_bin_size = 180
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, bin_name)
with open(binary_file, 'rb+') as f:
with open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+') as fo:
fo.write(f.read(truncated_bin_size))
binary_file = os.path.join(dut.app.binary_path, truncated_bin_name)
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
server_port = 8001 ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
# Original binary file generated after compilation print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
bin_name = 'advanced_https_ota.bin' except pexpect.exceptions.TIMEOUT:
# Truncated binary file to be generated from original binary file raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
truncated_bin_name = 'truncated_header.bin' # Start server
# Size of truncated file to be generated. This value should be less than 288 bytes (Image header size) host_ip = get_my_ip4_by_dest_ip(ip_address)
truncated_bin_size = 180 thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
# check and log bin size thread1.daemon = True
binary_file = os.path.join(dut.app.binary_path, bin_name) thread1.start()
with open(binary_file, 'rb+') as f:
with open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+') as fo:
fo.write(f.read(truncated_bin_size))
binary_file = os.path.join(dut.app.binary_path, truncated_bin_name) try:
# start test
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting Advanced OTA example', timeout=30) dut.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name)
dut.expect('advanced_https_ota_example: esp_https_ota_read_img_desc failed', timeout=30) dut.expect('advanced_https_ota_example: esp_https_ota_read_img_desc failed', timeout=30)
@@ -254,46 +247,46 @@ def test_examples_protocol_advanced_https_ota_example_truncated_header(dut: Dut)
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_advanced_https_ota_example_random(dut: Dut) -> None: def test_examples_protocol_advanced_https_ota_example_random(dut: Dut) -> None:
""" """
Working of OTA if random data is added in binary file are validated in this test case. Working of OTA if random data is added in binary file are validated in this test case.
Magic byte verification should fail in this case. Magic byte verification should fail in this case.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Generate random binary image 2. Generate random binary image
3. Fetch OTA image over HTTPS 3. Fetch OTA image over HTTPS
4. Check working of code for random binary file 4. Check working of code for random binary file
""" """
server_port = 8001
# Random binary file to be generated
random_bin_name = 'random.bin'
# Size of random binary file. 32000 is choosen, to reduce the time required to run the test-case
random_bin_size = 32000
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, random_bin_name)
with open(binary_file, 'wb+') as fo:
# First byte of binary file is always set to zero. If first byte is generated randomly,
# in some cases it may generate 0xE9 which will result in failure of testcase.
fo.write(struct.pack('B', 0))
for i in range(random_bin_size - 1):
fo.write(struct.pack('B', random.randrange(0,255,1)))
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
server_port = 8001 ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
# Random binary file to be generated print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
random_bin_name = 'random.bin' except pexpect.exceptions.TIMEOUT:
# Size of random binary file. 32000 is choosen, to reduce the time required to run the test-case raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
random_bin_size = 32000 # Start server
# check and log bin size host_ip = get_my_ip4_by_dest_ip(ip_address)
binary_file = os.path.join(dut.app.binary_path, random_bin_name) thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
with open(binary_file, 'wb+') as fo: thread1.daemon = True
# First byte of binary file is always set to zero. If first byte is generated randomly, thread1.start()
# in some cases it may generate 0xE9 which will result in failure of testcase.
fo.write(struct.pack('B', 0))
for i in range(random_bin_size - 1):
fo.write(struct.pack('B', random.randrange(0,255,1)))
# start test try:
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting Advanced OTA example', timeout=30) dut.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name)
dut.expect(r'esp_https_ota: Incorrect app descriptor magic', timeout=10) dut.expect(r'esp_https_ota: Incorrect app descriptor magic', timeout=10)
@@ -309,48 +302,48 @@ def test_examples_protocol_advanced_https_ota_example_random(dut: Dut) -> None:
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_advanced_https_ota_example_invalid_chip_id(dut: Dut) -> None: def test_examples_protocol_advanced_https_ota_example_invalid_chip_id(dut: Dut) -> None:
""" """
Working of OTA if binary file have invalid chip id is validated in this test case. Working of OTA if binary file have invalid chip id is validated in this test case.
Chip id verification should fail in this case. Chip id verification should fail in this case.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Generate binary image with invalid chip id 2. Generate binary image with invalid chip id
3. Fetch OTA image over HTTPS 3. Fetch OTA image over HTTPS
4. Check working of code for random binary file 4. Check working of code for random binary file
""" """
server_port = 8001
bin_name = 'advanced_https_ota.bin'
# Random binary file to be generated
random_bin_name = 'random.bin'
random_binary_file = os.path.join(dut.app.binary_path, random_bin_name)
# Size of random binary file. 2000 is choosen, to reduce the time required to run the test-case
random_bin_size = 2000
binary_file = os.path.join(dut.app.binary_path, bin_name)
with open(binary_file, 'rb+') as f:
data = list(f.read(random_bin_size))
# Changing Chip id
data[13] = 0xfe
with open(random_binary_file, 'wb+') as fo:
fo.write(bytearray(data))
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
server_port = 8001 ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
bin_name = 'advanced_https_ota.bin' print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
# Random binary file to be generated except pexpect.exceptions.TIMEOUT:
random_bin_name = 'random.bin' raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
random_binary_file = os.path.join(dut.app.binary_path, random_bin_name) # Start server
# Size of random binary file. 2000 is choosen, to reduce the time required to run the test-case host_ip = get_my_ip4_by_dest_ip(ip_address)
random_bin_size = 2000 thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
binary_file = os.path.join(dut.app.binary_path, bin_name) try:
with open(binary_file, 'rb+') as f:
data = list(f.read(random_bin_size))
# Changing Chip id
data[13] = 0xfe
with open(random_binary_file, 'wb+') as fo:
fo.write(bytearray(data))
# start test
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting Advanced OTA example', timeout=30) dut.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name)
dut.expect(r'esp_https_ota: Mismatch chip id, expected 0, found \d', timeout=10) dut.expect(r'esp_https_ota: Mismatch chip id, expected 0, found \d', timeout=10)
@@ -366,31 +359,31 @@ def test_examples_protocol_advanced_https_ota_example_invalid_chip_id(dut: Dut)
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_advanced_https_ota_example_chunked(dut: Dut) -> None: def test_examples_protocol_advanced_https_ota_example_chunked(dut: Dut) -> None:
""" """
This is a positive test case, which downloads complete binary file multiple number of times. This is a positive test case, which downloads complete binary file multiple number of times.
Number of iterations can be specified in variable iterations. Number of iterations can be specified in variable iterations.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
# File to be downloaded. This file is generated after compilation # File to be downloaded. This file is generated after compilation
bin_name = 'advanced_https_ota.bin' bin_name = 'advanced_https_ota.bin'
# start test # start test
host_ip = get_my_ip() dut.expect('Loaded app from partition at offset', timeout=30)
chunked_server = start_chunked_server(dut.app.binary_path, 8070)
try: try:
dut.expect('Loaded app from partition at offset', timeout=30) ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
try: print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30) except pexpect.exceptions.TIMEOUT:
print('Connected to AP/Ethernet with IP: {}'.format(ip_address)) raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
except pexpect.exceptions.TIMEOUT: # Start server
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet') host_ip = get_my_ip4_by_dest_ip(ip_address)
chunked_server = start_chunked_server(dut.app.binary_path, 8070)
try:
dut.expect('Starting Advanced OTA example', timeout=30) dut.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8070/' + bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':8070/' + bin_name))
dut.write('https://' + host_ip + ':8070/' + bin_name) dut.write('https://' + host_ip + ':8070/' + bin_name)
dut.expect('Loaded app from partition at offset', timeout=60) dut.expect('Loaded app from partition at offset', timeout=60)
@@ -403,46 +396,45 @@ def test_examples_protocol_advanced_https_ota_example_chunked(dut: Dut) -> None:
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_advanced_https_ota_example_redirect_url(dut: Dut) -> None: def test_examples_protocol_advanced_https_ota_example_redirect_url(dut: Dut) -> None:
""" """
This is a positive test case, which starts a server and a redirection server. This is a positive test case, which starts a server and a redirection server.
Redirection server redirects http_request to different port Redirection server redirects http_request to different port
Number of iterations can be specified in variable iterations. Number of iterations can be specified in variable iterations.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
server_port = 8001
# Port to which the request should be redirected
redirection_server_port = 8081
redirection_server_port1 = 8082
# File to be downloaded. This file is generated after compilation
bin_name = 'advanced_https_ota.bin'
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
server_port = 8001 ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
# Port to which the request should be redirected print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
redirection_server_port = 8081 except pexpect.exceptions.TIMEOUT:
redirection_server_port1 = 8082 raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# File to be downloaded. This file is generated after compilation dut.expect('Starting Advanced OTA example', timeout=30)
bin_name = 'advanced_https_ota.bin'
# start test
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
thread2 = multiprocessing.Process(target=start_redirect_server, args=(dut.app.binary_path, host_ip, redirection_server_port, redirection_server_port1))
thread2.daemon = True
thread2.start()
thread3 = multiprocessing.Process(target=start_redirect_server, args=(dut.app.binary_path, host_ip, redirection_server_port1, server_port))
thread3.daemon = True
thread3.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
thread2.terminate()
thread3.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting Advanced OTA example', timeout=30)
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread2 = multiprocessing.Process(target=start_redirect_server, args=(dut.app.binary_path, host_ip, redirection_server_port, redirection_server_port1))
thread2.daemon = True
thread3 = multiprocessing.Process(target=start_redirect_server, args=(dut.app.binary_path, host_ip, redirection_server_port1, server_port))
thread3.daemon = True
try:
thread1.start()
thread2.start()
thread3.start()
print('writing to device: {}'.format('https://' + host_ip + ':' + str(redirection_server_port) + '/' + bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(redirection_server_port) + '/' + bin_name))
dut.write('https://' + host_ip + ':' + str(redirection_server_port) + '/' + bin_name) dut.write('https://' + host_ip + ':' + str(redirection_server_port) + '/' + bin_name)
dut.expect('Loaded app from partition at offset', timeout=60) dut.expect('Loaded app from partition at offset', timeout=60)
@@ -465,49 +457,49 @@ def test_examples_protocol_advanced_https_ota_example_anti_rollback(dut: Dut) ->
Working of OTA when anti_rollback is enabled and security version of new image is less than current one. Working of OTA when anti_rollback is enabled and security version of new image is less than current one.
Application should return with error message in this case. Application should return with error message in this case.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Generate binary file with lower security version 2. Generate binary file with lower security version
3. Fetch OTA image over HTTPS 3. Fetch OTA image over HTTPS
4. Check working of anti_rollback feature 4. Check working of anti_rollback feature
""" """
dut.serial.erase_flash()
dut.serial.flash()
server_port = 8001
# Original binary file generated after compilation
bin_name = 'advanced_https_ota.bin'
# Modified firmware image to lower security version in its header. This is to enable negative test case
anti_rollback_bin_name = 'advanced_https_ota_lower_sec_version.bin'
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, bin_name)
file_size = os.path.getsize(binary_file)
with open(binary_file, 'rb+') as f:
with open(os.path.join(dut.app.binary_path, anti_rollback_bin_name), 'wb+') as fo:
fo.write(f.read(file_size))
# Change security_version to 0 for negative test case
fo.seek(36)
fo.write(b'\x00')
binary_file = os.path.join(dut.app.binary_path, anti_rollback_bin_name)
# start test
# Positive Case
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
dut.serial.erase_flash() ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
dut.serial.flash() print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
server_port = 8001 except pexpect.exceptions.TIMEOUT:
# Original binary file generated after compilation raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
bin_name = 'advanced_https_ota.bin' # Start server
# Modified firmware image to lower security version in its header. This is to enable negative test case host_ip = get_my_ip4_by_dest_ip(ip_address)
anti_rollback_bin_name = 'advanced_https_ota_lower_sec_version.bin' thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
# check and log bin size thread1.daemon = True
binary_file = os.path.join(dut.app.binary_path, bin_name) thread1.start()
file_size = os.path.getsize(binary_file)
with open(binary_file, 'rb+') as f:
with open(os.path.join(dut.app.binary_path, anti_rollback_bin_name), 'wb+') as fo:
fo.write(f.read(file_size))
# Change security_version to 0 for negative test case
fo.seek(36)
fo.write(b'\x00')
binary_file = os.path.join(dut.app.binary_path, anti_rollback_bin_name)
# start test
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
# Positive Case
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting Advanced OTA example', timeout=30)
try:
dut.expect('Starting Advanced OTA example', timeout=30)
# Use originally generated image with secure_version=1 # Use originally generated image with secure_version=1
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)
dut.expect('Loaded app from partition at offset', timeout=60) dut.expect('Loaded app from partition at offset', timeout=60)
dut.expect(r' (sta|eth) ip: ([^,]+),', timeout=30) dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
dut.expect(r'App is valid, rollback cancelled successfully', timeout=30) dut.expect(r'App is valid, rollback cancelled successfully', timeout=30)
# Negative Case # Negative Case
@@ -528,47 +520,47 @@ def test_examples_protocol_advanced_https_ota_example_anti_rollback(dut: Dut) ->
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
@pytest.mark.parametrize('config', ['partial_download',], indirect=True) @pytest.mark.parametrize('config', ['partial_download',], indirect=True)
def test_examples_protocol_advanced_https_ota_example_partial_request(dut: Dut) -> None: def test_examples_protocol_advanced_https_ota_example_partial_request(dut: Dut) -> None:
""" """
This is a positive test case, to test OTA workflow with Range HTTP header. This is a positive test case, to test OTA workflow with Range HTTP header.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
server_port = 8001
# Size of partial HTTP request
request_size = 16384
# File to be downloaded. This file is generated after compilation
bin_name = 'advanced_https_ota.bin'
binary_file = os.path.join(dut.app.binary_path, bin_name)
bin_size = os.path.getsize(binary_file)
http_requests = int((bin_size / request_size) - 1)
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
server_port = 8001 ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
# Size of partial HTTP request print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
request_size = 16384 except pexpect.exceptions.TIMEOUT:
# File to be downloaded. This file is generated after compilation print('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
bin_name = 'advanced_https_ota.bin' raise
binary_file = os.path.join(dut.app.binary_path, bin_name) # Start server
bin_size = os.path.getsize(binary_file) host_ip = get_my_ip4_by_dest_ip(ip_address)
http_requests = int((bin_size / request_size) - 1) thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
# start test thread1.daemon = True
host_ip = get_my_ip() thread1.start()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
print('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
thread1.terminate()
raise
dut.expect('Starting Advanced OTA example', timeout=30)
try:
dut.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)
for _ in range(http_requests): for _ in range(http_requests):
dut.expect('Connection closed', timeout=60) dut.expect('Connection closed', timeout=60)
dut.expect('Loaded app from partition at offset', timeout=60) dut.expect('Loaded app from partition at offset', timeout=60)
dut.expect('Starting Advanced OTA example', timeout=30) dut.expect('Starting Advanced OTA example', timeout=30)
finally: except:
thread1.terminate() thread1.terminate()
@@ -583,27 +575,29 @@ def test_examples_protocol_advanced_https_ota_example_nimble_gatts(dut: Dut) ->
""" """
Run an OTA image update while a BLE GATT Server is running in background. This GATT server will be using NimBLE Host stack. Run an OTA image update while a BLE GATT Server is running in background. This GATT server will be using NimBLE Host stack.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Run BLE advertise and then GATT server. 2. Run BLE advertise and then GATT server.
3. Fetch OTA image over HTTPS 3. Fetch OTA image over HTTPS
4. Reboot with the new OTA image 4. Reboot with the new OTA image
""" """
server_port = 8001
# File to be downloaded. This file is generated after compilation
bin_name = 'advanced_https_ota.bin'
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
server_port = 8001 ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
# File to be downloaded. This file is generated after compilation print('Connected to AP with IP: {}'.format(ip_address))
bin_name = 'advanced_https_ota.bin' except pexpect.exceptions.TIMEOUT:
# start test raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
try:
dut.expect('Starting Advanced OTA example', timeout=30) dut.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name))
print('Started GAP advertising.') print('Started GAP advertising.')
@@ -611,7 +605,7 @@ def test_examples_protocol_advanced_https_ota_example_nimble_gatts(dut: Dut) ->
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)
dut.expect('Loaded app from partition at offset', timeout=60) dut.expect('Loaded app from partition at offset', timeout=60)
dut.expect('Starting Advanced OTA example', timeout=30) dut.expect('Starting Advanced OTA example', timeout=30)
finally: except:
thread1.terminate() thread1.terminate()
@@ -626,28 +620,29 @@ def test_examples_protocol_advanced_https_ota_example_bluedroid_gatts(dut: Dut)
""" """
Run an OTA image update while a BLE GATT Server is running in background. This GATT server will be using Bluedroid Host stack. Run an OTA image update while a BLE GATT Server is running in background. This GATT server will be using Bluedroid Host stack.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Run BLE advertise and then GATT server. 2. Run BLE advertise and then GATT server.
3. Fetch OTA image over HTTPS 3. Fetch OTA image over HTTPS
4. Reboot with the new OTA image 4. Reboot with the new OTA image
""" """
server_port = 8001
# File to be downloaded. This file is generated after compilation
bin_name = 'advanced_https_ota.bin'
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
server_port = 8001 ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
# File to be downloaded. This file is generated after compilation print('Connected to AP with IP: {}'.format(ip_address))
bin_name = 'advanced_https_ota.bin' except pexpect.exceptions.TIMEOUT:
# start test raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP')
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
try:
dut.expect('Starting Advanced OTA example', timeout=30) dut.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name))
dut.expect('Started advertising.', timeout=30) dut.expect('Started advertising.', timeout=30)
@@ -664,12 +659,12 @@ def test_examples_protocol_advanced_https_ota_example_bluedroid_gatts(dut: Dut)
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_advanced_https_ota_example_openssl_aligned_bin(dut: Dut) -> None: def test_examples_protocol_advanced_https_ota_example_openssl_aligned_bin(dut: Dut) -> None:
""" """
This is a test case for esp_http_client_read with binary size multiple of 289 bytes This is a test case for esp_http_client_read with binary size multiple of 289 bytes
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
@@ -689,18 +684,18 @@ def test_examples_protocol_advanced_https_ota_example_openssl_aligned_bin(dut: D
for _ in range(dummy_data_size): for _ in range(dummy_data_size):
fo.write(struct.pack('B', random.randrange(0,255,1))) fo.write(struct.pack('B', random.randrange(0,255,1)))
# start test # start test
host_ip = get_my_ip() dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
chunked_server = start_chunked_server(dut.app.binary_path, 8070) chunked_server = start_chunked_server(dut.app.binary_path, 8070)
try: try:
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting Advanced OTA example', timeout=30) dut.expect('Starting Advanced OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8070/' + aligned_bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':8070/' + aligned_bin_name))
dut.write('https://' + host_ip + ':8070/' + aligned_bin_name) dut.write('https://' + host_ip + ':8070/' + aligned_bin_name)
dut.expect('Loaded app from partition at offset', timeout=60) dut.expect('Loaded app from partition at offset', timeout=60)

View File

@@ -12,6 +12,7 @@ from typing import Callable, Tuple
import pexpect import pexpect
import pytest import pytest
from common_test_methods import get_my_ip4_by_dest_ip
from pytest_embedded import Dut from pytest_embedded import Dut
server_cert = '-----BEGIN CERTIFICATE-----\n' \ server_cert = '-----BEGIN CERTIFICATE-----\n' \
@@ -65,15 +66,6 @@ server_key = '-----BEGIN PRIVATE KEY-----\n'\
'-----END PRIVATE KEY-----\n' '-----END PRIVATE KEY-----\n'
def get_my_ip() -> str:
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s1.connect(('8.8.8.8', 80))
my_ip = ''
my_ip = s1.getsockname()[0]
s1.close()
return my_ip
def create_file(server_file: str, file_data: str) -> None: def create_file(server_file: str, file_data: str) -> None:
with open(server_file, 'w+') as file: with open(server_file, 'w+') as file:
file.write(file_data) file.write(file_data)
@@ -130,86 +122,84 @@ def start_chunked_server(ota_image_dir: str, server_port: int) -> subprocess.Pop
@pytest.mark.supported_targets @pytest.mark.supported_targets
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_native_ota_example(dut: Dut) -> None: def test_examples_protocol_native_ota_example(dut: Dut) -> None:
""" """
This is a positive test case, which downloads complete binary file multiple number of times. This is a positive test case, which downloads complete binary file multiple number of times.
Number of iterations can be specified in variable iterations. Number of iterations can be specified in variable iterations.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
try: server_port = 8002
server_port = 8002 # No. of times working of application to be validated
# No. of times working of application to be validated iterations = 3
iterations = 3 # File to be downloaded. This file is generated after compilation
# File to be downloaded. This file is generated after compilation bin_name = 'native_ota.bin'
bin_name = 'native_ota.bin' # start test
# start test for _ in range(iterations):
host_ip = get_my_ip() dut.expect('Loaded app from partition at offset', timeout=60)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port)) thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True thread1.daemon = True
thread1.start() thread1.start()
for i in range(iterations): try:
dut.expect('Loaded app from partition at offset', timeout=60)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30) dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + bin_name)
finally: finally:
thread1.terminate() thread1.terminate()
@pytest.mark.supported_targets @pytest.mark.supported_targets
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_native_ota_example_truncated_bin(dut: Dut) -> None: def test_examples_protocol_native_ota_example_truncated_bin(dut: Dut) -> None:
""" """
Working of OTA if binary file is truncated is validated in this test case. Working of OTA if binary file is truncated is validated in this test case.
Application should return with error message in this case. Application should return with error message in this case.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Generate truncated binary file 2. Generate truncated binary file
3. Fetch OTA image over HTTPS 3. Fetch OTA image over HTTPS
4. Check working of code if bin is truncated 4. Check working of code if bin is truncated
""" """
server_port = 8002
# Original binary file generated after compilation
bin_name = 'native_ota.bin'
# Truncated binary file to be generated from original binary file
truncated_bin_name = 'truncated.bin'
# Size of truncated file to be grnerated. This value can range from 288 bytes (Image header size) to size of original binary file
# truncated_bin_size is set to 64000 to reduce consumed by the test case
truncated_bin_size = 64000
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, bin_name)
f = open(binary_file, 'rb+')
fo = open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+')
fo.write(f.read(truncated_bin_size))
fo.close()
f.close()
binary_file = os.path.join(dut.app.binary_path, truncated_bin_name)
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
try: try:
server_port = 8002
# Original binary file generated after compilation
bin_name = 'native_ota.bin'
# Truncated binary file to be generated from original binary file
truncated_bin_name = 'truncated.bin'
# Size of truncated file to be grnerated. This value can range from 288 bytes (Image header size) to size of original binary file
# truncated_bin_size is set to 64000 to reduce consumed by the test case
truncated_bin_size = 64000
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, bin_name)
f = open(binary_file, 'rb+')
fo = open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+')
fo.write(f.read(truncated_bin_size))
fo.close()
f.close()
binary_file = os.path.join(dut.app.binary_path, truncated_bin_name)
# start test
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30) dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name)
dut.expect('native_ota_example: Image validation failed, image is corrupted', timeout=20) dut.expect('native_ota_example: Image validation failed, image is corrupted', timeout=20)
@@ -219,47 +209,46 @@ def test_examples_protocol_native_ota_example_truncated_bin(dut: Dut) -> None:
@pytest.mark.supported_targets @pytest.mark.supported_targets
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_native_ota_example_truncated_header(dut: Dut) -> None: def test_examples_protocol_native_ota_example_truncated_header(dut: Dut) -> None:
""" """
Working of OTA if headers of binary file are truncated is vaildated in this test case. Working of OTA if headers of binary file are truncated is vaildated in this test case.
Application should return with error message in this case. Application should return with error message in this case.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Generate binary file with truncated headers 2. Generate binary file with truncated headers
3. Fetch OTA image over HTTPS 3. Fetch OTA image over HTTPS
4. Check working of code if headers are not sent completely 4. Check working of code if headers are not sent completely
""" """
server_port = 8002
# Original binary file generated after compilation
bin_name = 'native_ota.bin'
# Truncated binary file to be generated from original binary file
truncated_bin_name = 'truncated_header.bin'
# Size of truncated file to be grnerated. This value should be less than 288 bytes (Image header size)
truncated_bin_size = 180
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, bin_name)
f = open(binary_file, 'rb+')
fo = open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+')
fo.write(f.read(truncated_bin_size))
fo.close()
f.close()
binary_file = os.path.join(dut.app.binary_path, truncated_bin_name)
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
try: try:
server_port = 8002
# Original binary file generated after compilation
bin_name = 'native_ota.bin'
# Truncated binary file to be generated from original binary file
truncated_bin_name = 'truncated_header.bin'
# Size of truncated file to be grnerated. This value should be less than 288 bytes (Image header size)
truncated_bin_size = 180
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, bin_name)
f = open(binary_file, 'rb+')
fo = open(os.path.join(dut.app.binary_path, truncated_bin_name), 'wb+')
fo.write(f.read(truncated_bin_size))
fo.close()
f.close()
binary_file = os.path.join(dut.app.binary_path, truncated_bin_name)
# start test
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30) dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + truncated_bin_name)
dut.expect('native_ota_example: received package is not fit len', timeout=20) dut.expect('native_ota_example: received package is not fit len', timeout=20)
@@ -269,46 +258,46 @@ def test_examples_protocol_native_ota_example_truncated_header(dut: Dut) -> None
@pytest.mark.supported_targets @pytest.mark.supported_targets
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_native_ota_example_random(dut: Dut) -> None: def test_examples_protocol_native_ota_example_random(dut: Dut) -> None:
""" """
Working of OTA if random data is added in binary file are validated in this test case. Working of OTA if random data is added in binary file are validated in this test case.
Magic byte verification should fail in this case. Magic byte verification should fail in this case.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Generate random binary image 2. Generate random binary image
3. Fetch OTA image over HTTPS 3. Fetch OTA image over HTTPS
4. Check working of code for random binary file 4. Check working of code for random binary file
""" """
server_port = 8002
# Random binary file to be generated
random_bin_name = 'random.bin'
# Size of random binary file. 32000 is choosen, to reduce the time required to run the test-case
random_bin_size = 32000
# check and log bin size
binary_file = os.path.join(dut.app.binary_path, random_bin_name)
fo = open(binary_file, 'wb+')
# First byte of binary file is always set to zero. If first byte is generated randomly,
# in some cases it may generate 0xE9 which will result in failure of testcase.
fo.write(struct.pack('B', 0))
for i in range(random_bin_size - 1):
fo.write(struct.pack('B', random.randrange(0,255,1)))
fo.close()
# start test
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
server_port = 8002 ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
# Random binary file to be generated print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
random_bin_name = 'random.bin' except pexpect.exceptions.TIMEOUT:
# Size of random binary file. 32000 is choosen, to reduce the time required to run the test-case raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
random_bin_size = 32000 # Start server
# check and log bin size host_ip = get_my_ip4_by_dest_ip(ip_address)
binary_file = os.path.join(dut.app.binary_path, random_bin_name) thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
fo = open(binary_file, 'wb+') thread1.daemon = True
# First byte of binary file is always set to zero. If first byte is generated randomly, thread1.start()
# in some cases it may generate 0xE9 which will result in failure of testcase.
fo.write(struct.pack('B', 0))
for i in range(random_bin_size - 1):
fo.write(struct.pack('B', random.randrange(0,255,1)))
fo.close()
# start test
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30)
try:
dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + random_bin_name)
dut.expect('esp_ota_ops: OTA image has invalid magic byte', timeout=20) dut.expect('esp_ota_ops: OTA image has invalid magic byte', timeout=20)
@@ -318,29 +307,29 @@ def test_examples_protocol_native_ota_example_random(dut: Dut) -> None:
@pytest.mark.supported_targets @pytest.mark.supported_targets
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_native_ota_example_chunked(dut: Dut) -> None: def test_examples_protocol_native_ota_example_chunked(dut: Dut) -> None:
""" """
This is a positive test case, which downloads complete binary file multiple number of times. This is a positive test case, which downloads complete binary file multiple number of times.
Number of iterations can be specified in variable iterations. Number of iterations can be specified in variable iterations.
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
# File to be downloaded. This file is generated after compilation # File to be downloaded. This file is generated after compilation
bin_name = 'native_ota.bin' bin_name = 'native_ota.bin'
# start test # start test
host_ip = get_my_ip() dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)[1].decode()
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
chunked_server = start_chunked_server(dut.app.binary_path, 8070) chunked_server = start_chunked_server(dut.app.binary_path, 8070)
try: try:
dut.expect('Loaded app from partition at offset', timeout=30)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30) dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8070/' + bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':8070/' + bin_name))
dut.write('https://' + host_ip + ':8070/' + bin_name) dut.write('https://' + host_ip + ':8070/' + bin_name)

View File

@@ -9,6 +9,7 @@ from typing import Callable
import pexpect import pexpect
import pytest import pytest
from common_test_methods import get_my_ip4_by_dest_ip
from pytest_embedded import Dut from pytest_embedded import Dut
from RangeHTTPServer import RangeRequestHandler from RangeHTTPServer import RangeRequestHandler
@@ -17,15 +18,6 @@ key_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'server_cert
enc_bin_name = 'pre_encrypted_ota_secure.bin' enc_bin_name = 'pre_encrypted_ota_secure.bin'
def get_my_ip() -> str:
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s1.connect(('8.8.8.8', 80))
my_ip = ''
my_ip = s1.getsockname()[0]
s1.close()
return my_ip
def https_request_handler() -> Callable[...,http.server.BaseHTTPRequestHandler]: def https_request_handler() -> Callable[...,http.server.BaseHTTPRequestHandler]:
""" """
Returns a request handler class that handles broken pipe exception Returns a request handler class that handles broken pipe exception
@@ -64,25 +56,24 @@ def start_https_server(ota_image_dir: str, server_ip: str, server_port: int) ->
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
def test_examples_protocol_pre_encrypted_ota_example(dut: Dut) -> None: def test_examples_protocol_pre_encrypted_ota_example(dut: Dut) -> None:
server_port = 8001
dut.expect('Loaded app from partition at offset', timeout=30)
try: try:
server_port = 8001 ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
# start test print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
host_ip = get_my_ip() except pexpect.exceptions.TIMEOUT:
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port)) thread1.terminate()
thread1.daemon = True raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
thread1.start() # Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, server_port))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset', timeout=30) try:
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting Pre Encrypted OTA example', timeout=30) dut.expect('Starting Pre Encrypted OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + enc_bin_name)) print('writing to device: {}'.format('https://' + host_ip + ':' + str(server_port) + '/' + enc_bin_name))
dut.write('https://' + host_ip + ':' + str(server_port) + '/' + enc_bin_name) dut.write('https://' + host_ip + ':' + str(server_port) + '/' + enc_bin_name)
dut.expect('Magic Verified', timeout=30) dut.expect('Magic Verified', timeout=30)

View File

@@ -10,6 +10,7 @@ from typing import Tuple
import pexpect import pexpect
import pytest import pytest
from common_test_methods import get_my_ip4_by_dest_ip
from pytest_embedded import Dut from pytest_embedded import Dut
server_cert = '-----BEGIN CERTIFICATE-----\n' \ server_cert = '-----BEGIN CERTIFICATE-----\n' \
@@ -63,15 +64,6 @@ server_key = '-----BEGIN PRIVATE KEY-----\n'\
'-----END PRIVATE KEY-----\n' '-----END PRIVATE KEY-----\n'
def get_my_ip() -> str:
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s1.connect(('8.8.8.8', 80))
my_ip = ''
my_ip = s1.getsockname()[0]
s1.close()
return my_ip
def start_https_server(ota_image_dir: str, server_ip: str, server_port: int, server_file: str = None, key_file: str = None) -> None: def start_https_server(ota_image_dir: str, server_ip: str, server_port: int, server_file: str = None, key_file: str = None) -> None:
os.chdir(ota_image_dir) os.chdir(ota_image_dir)
@@ -123,28 +115,28 @@ def calc_all_sha256(dut: Dut) -> Tuple[str, str]:
def test_examples_protocol_simple_ota_example(dut: Dut) -> None: def test_examples_protocol_simple_ota_example(dut: Dut) -> None:
""" """
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
sha256_bootloader, sha256_app = calc_all_sha256(dut)
# start test
dut.expect('Loaded app from partition at offset 0x10000', timeout=30)
check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0]))
check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0]))
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000))
thread1.daemon = True
thread1.start()
try: try:
sha256_bootloader, sha256_app = calc_all_sha256(dut)
# start test
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset 0x10000', timeout=30)
check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0]))
check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0]))
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30) dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
dut.write('https://' + host_ip + ':8000/simple_ota.bin') dut.write('https://' + host_ip + ':8000/simple_ota.bin')
dut.expect('Loaded app from partition at offset 0x110000', timeout=60) dut.expect('Loaded app from partition at offset 0x110000', timeout=60)
@@ -157,30 +149,30 @@ def test_examples_protocol_simple_ota_example(dut: Dut) -> None:
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
@pytest.mark.parametrize('config', ['spiram',], indirect=True) @pytest.mark.parametrize('config', ['spiram',], indirect=True)
def test_examples_protocol_simple_ota_example_ethernet_with_spiram_config(dut: Dut) -> None: def test_examples_protocol_simple_ota_example_ethernet_with_spiram_config(dut: Dut) -> None:
""" """
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
# start test
dut.expect('Loaded app from partition at offset 0x10000', timeout=30))
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000))
thread1.daemon = True
thread1.start()
try: try:
# start test
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset 0x10000', timeout=30))
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30) dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
dut.write('https://' + host_ip + ':8000/simple_ota.bin') dut.write('https://' + host_ip + ':8000/simple_ota.bin')
dut.expect('Loaded app from partition at offset 0x110000', timeout=60) dut.expect('Loaded app from partition at offset 0x110000', timeout=60)
@@ -199,29 +191,29 @@ def test_examples_protocol_simple_ota_example_ethernet_with_spiram_config(dut: D
def test_examples_protocol_simple_ota_example_with_flash_encryption(dut: Dut) -> None: def test_examples_protocol_simple_ota_example_with_flash_encryption(dut: Dut) -> None:
""" """
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
# Erase flash
dut.serial.erase_flash()
dut.serial.flash()
# start test
dut.expect('Loaded app from partition at offset 0x20000', timeout=30)
dut.expect('Flash encryption mode is DEVELOPMENT', timeout=10)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000))
thread1.daemon = True
thread1.start()
try: try:
# Erase flash
dut.serial.erase_flash()
dut.serial.flash()
# start test
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset 0x20000', timeout=30)
dut.expect('Flash encryption mode is DEVELOPMENT', timeout=10)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30) dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
dut.write('https://' + host_ip + ':8000/simple_ota.bin') dut.write('https://' + host_ip + ':8000/simple_ota.bin')
dut.expect('Loaded app from partition at offset 0x120000', timeout=60) dut.expect('Loaded app from partition at offset 0x120000', timeout=60)
@@ -239,29 +231,29 @@ def test_examples_protocol_simple_ota_example_with_flash_encryption(dut: Dut) ->
def test_examples_protocol_simple_ota_example_with_flash_encryption_wifi(dut: Dut) -> None: def test_examples_protocol_simple_ota_example_with_flash_encryption_wifi(dut: Dut) -> None:
""" """
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
# start test
# Erase flash
dut.serial.erase_flash()
dut.serial.flash()
dut.expect('Loaded app from partition at offset 0x20000', timeout=30)
dut.expect('Flash encryption mode is DEVELOPMENT', timeout=10)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
# Start server
host_ip = get_my_ip4_by_dest_ip(ip_address)
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000))
thread1.daemon = True
thread1.start()
try: try:
# start test
# Erase flash
dut.serial.erase_flash()
dut.serial.flash()
host_ip = get_my_ip()
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000))
thread1.daemon = True
thread1.start()
dut.expect('Loaded app from partition at offset 0x20000', timeout=30)
dut.expect('Flash encryption mode is DEVELOPMENT', timeout=10)
try:
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30) dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
dut.write('https://' + host_ip + ':8000/simple_ota.bin') dut.write('https://' + host_ip + ':8000/simple_ota.bin')
dut.expect('Loaded app from partition at offset 0x120000', timeout=60) dut.expect('Loaded app from partition at offset 0x120000', timeout=60)
@@ -275,39 +267,38 @@ def test_examples_protocol_simple_ota_example_with_flash_encryption_wifi(dut: Du
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet_ota @pytest.mark.ethernet_router
@pytest.mark.parametrize('config', ['on_update_no_sb_ecdsa',], indirect=True) @pytest.mark.parametrize('config', ['on_update_no_sb_ecdsa',], indirect=True)
def test_examples_protocol_simple_ota_example_with_verify_app_signature_on_update_no_secure_boot_ecdsa(dut: Dut) -> None: def test_examples_protocol_simple_ota_example_with_verify_app_signature_on_update_no_secure_boot_ecdsa(dut: Dut) -> None:
""" """
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
sha256_bootloader, sha256_app = calc_all_sha256(dut)
# start test
dut.expect('Loaded app from partition at offset 0x20000', timeout=30)
check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0]))
check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0]))
try: try:
sha256_bootloader, sha256_app = calc_all_sha256(dut) ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
# start test print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
host_ip = get_my_ip() except pexpect.exceptions.TIMEOUT:
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000)) thread1.terminate()
thread1.daemon = True raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
thread1.start() # Start server
dut.expect('Loaded app from partition at offset 0x20000', timeout=30) host_ip = get_my_ip4_by_dest_ip(ip_address)
check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0])) thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000))
check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0])) thread1.daemon = True
try: thread1.start()
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30)
try:
dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
dut.write('https://' + host_ip + ':8000/simple_ota.bin') dut.write('https://' + host_ip + ':8000/simple_ota.bin')
dut.expect('Writing to partition subtype 16 at offset 0x120000', timeout=20) dut.expect('Writing to partition subtype 16 at offset 0x120000', timeout=20)
dut.expect('Verifying image signature...', timeout=60) dut.expect('Verifying image signature...', timeout=60)
dut.expect('Loaded app from partition at offset 0x120000', timeout=20) dut.expect('Loaded app from partition at offset 0x120000', timeout=20)
dut.expect('Starting OTA example', timeout=30) dut.expect('Starting OTA example', timeout=30)
finally: finally:
@@ -318,33 +309,34 @@ def test_examples_protocol_simple_ota_example_with_verify_app_signature_on_updat
@pytest.mark.esp32c3 @pytest.mark.esp32c3
@pytest.mark.esp32s2 @pytest.mark.esp32s2
@pytest.mark.esp32s3 @pytest.mark.esp32s3
@pytest.mark.ethernet @pytest.mark.ethernet_router
@pytest.mark.parametrize('config', ['on_update_no_sb_rsa',], indirect=True) @pytest.mark.parametrize('config', ['on_update_no_sb_rsa',], indirect=True)
def test_examples_protocol_simple_ota_example_with_verify_app_signature_on_update_no_secure_boot_rsa(dut: Dut) -> None: def test_examples_protocol_simple_ota_example_with_verify_app_signature_on_update_no_secure_boot_rsa(dut: Dut) -> None:
""" """
steps: | steps: |
1. join AP 1. join AP/Ethernet
2. Fetch OTA image over HTTPS 2. Fetch OTA image over HTTPS
3. Reboot with the new OTA image 3. Reboot with the new OTA image
""" """
sha256_bootloader, sha256_app = calc_all_sha256(dut)
# start test
dut.expect('Loaded app from partition at offset 0x20000', timeout=30)
check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0]))
check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0]))
try: try:
sha256_bootloader, sha256_app = calc_all_sha256(dut) ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
# start test print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
host_ip = get_my_ip() except pexpect.exceptions.TIMEOUT:
thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000)) thread1.terminate()
thread1.daemon = True raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
thread1.start() # Start server
dut.expect('Loaded app from partition at offset 0x20000', timeout=30) host_ip = get_my_ip4_by_dest_ip(ip_address)
check_sha256(sha256_bootloader, str(dut.expect(r'SHA-256 for bootloader:\s+([a-f0-9]){64}')[0])) thread1 = multiprocessing.Process(target=start_https_server, args=(dut.app.binary_path, host_ip, 8000))
check_sha256(sha256_app, str(dut.expect(r'SHA-256 for current firmware:\s+([a-f0-9]){64}')[0])) thread1.daemon = True
try: thread1.start()
ip_address = dut.expect(r'IPv4 address: ([^,]+),', timeout=30)
print('Connected to AP/Ethernet with IP: {}'.format(ip_address))
except pexpect.exceptions.TIMEOUT:
thread1.terminate()
raise ValueError('ENV_TEST_FAILURE: Cannot connect to AP/Ethernet')
dut.expect('Starting OTA example', timeout=30)
try:
dut.expect('Starting OTA example', timeout=30)
print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin')) print('writing to device: {}'.format('https://' + host_ip + ':8000/simple_ota.bin'))
dut.write('https://' + host_ip + ':8000/simple_ota.bin') dut.write('https://' + host_ip + ':8000/simple_ota.bin')
dut.expect('Writing to partition subtype 16 at offset 0x120000', timeout=20) dut.expect('Writing to partition subtype 16 at offset 0x120000', timeout=20)

View File

@@ -36,7 +36,6 @@ markers =
quad_psram: runners with quad psram quad_psram: runners with quad psram
octal_psram: runners with octal psram octal_psram: runners with octal psram
usb_host: usb host runners usb_host: usb host runners
ethernet_ota: ethernet OTA runners
flash_encryption: Flash Encryption runners flash_encryption: Flash Encryption runners
ir_transceiver: runners with a pair of IR transmitter and receiver ir_transceiver: runners with a pair of IR transmitter and receiver
wifi_ota: wifi OTA runners wifi_ota: wifi OTA runners
@@ -44,15 +43,17 @@ markers =
flash_encryption_wifi_ota: flash encryprion ota wifi runner flash_encryption_wifi_ota: flash encryprion ota wifi runner
ethernet: ethernet runner ethernet: ethernet runner
ethernet_flash_8m: ethernet runner with 8mb flash ethernet_flash_8m: ethernet runner with 8mb flash
wifi: wifi runner ethernet_router: both the runner and dut connect to the same router
wifi_bt: wifi runner with bluetooth wifi_nearby: runner with a wifi AP nearby
wifi_router: runner can connect to the dut by a wifi router
wifi_wlan: wifi runner with a wireless NIC
deepsleep_temp_tag: temporary env for running potentially harmfull deepsleep related tests deepsleep_temp_tag: temporary env for running potentially harmfull deepsleep related tests
# multi-dut markers # multi-dut markers
multi_dut_generic: tests should be run on generic runners, at least have two duts connected. multi_dut_generic: tests should be run on generic runners, at least have two duts connected.
# host_test markers # host_test markers
host_test: tests which shouldn't be built at the build stage, and instead built in host_test stage. host_test: tests which shouldn not be built at the build stage, and instead built in host_test stage.
qemu: build and test using qemu-system-xtensa, not real target. qemu: build and test using qemu-system-xtensa, not real target.
# log related # log related

View File

@@ -15,6 +15,7 @@ from threading import Event, Lock, Thread
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
import ttfw_idf import ttfw_idf
from common_test_methods import get_my_ip4_by_dest_ip
DEFAULT_MSG_SIZE = 16 DEFAULT_MSG_SIZE = 16
@@ -33,19 +34,6 @@ def set_server_cert_cn(ip):
raise('openssl command {} failed'.format(args)) raise('openssl command {} failed'.format(args))
def get_my_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
# Publisher class creating a python client to send/receive published data from esp-mqtt client # Publisher class creating a python client to send/receive published data from esp-mqtt client
class MqttPublisher: class MqttPublisher:
@@ -247,8 +235,8 @@ class TlsServer:
self.shutdown.set() self.shutdown.set()
def connection_tests(dut, cases): def connection_tests(dut, cases, dut_ip):
ip = get_my_ip() ip = get_my_ip4_by_dest_ip(dut_ip)
set_server_cert_cn(ip) set_server_cert_cn(ip)
server_port = 2222 server_port = 2222
@@ -314,7 +302,7 @@ def connection_tests(dut, cases):
teardown_connection_suite() teardown_connection_suite()
@ttfw_idf.idf_custom_test(env_tag='Example_EthKitV1', group='test-apps') @ttfw_idf.idf_custom_test(env_tag='ethernet_router', group='test-apps')
def test_app_protocol_mqtt_publish_connect(env, extra_data): def test_app_protocol_mqtt_publish_connect(env, extra_data):
""" """
steps: steps:
@@ -348,11 +336,11 @@ def test_app_protocol_mqtt_publish_connect(env, extra_data):
raise raise
dut1.start_app() dut1.start_app()
esp_ip = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30) esp_ip = dut1.expect(re.compile(r' IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)'), timeout=30)[0]
print('Got IP={}'.format(esp_ip[0])) print('Got IP={}'.format(esp_ip))
if not os.getenv('MQTT_SKIP_CONNECT_TEST'): if not os.getenv('MQTT_SKIP_CONNECT_TEST'):
connection_tests(dut1,cases) connection_tests(dut1,cases,esp_ip)
# #
# start publish tests only if enabled in the environment (for weekend tests only) # start publish tests only if enabled in the environment (for weekend tests only)