diff --git a/.github/workflows/examples_build-host-test.yml b/.github/workflows/examples_build-host-test.yml index 8fea131b84..0084083160 100644 --- a/.github/workflows/examples_build-host-test.yml +++ b/.github/workflows/examples_build-host-test.yml @@ -13,12 +13,15 @@ jobs: name: Build examples strategy: matrix: - idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3"] + idf_ver: ["latest", "release-v5.1", "release-v5.2", "release-v5.3", "release-v5.4"] include: - idf_ver: "latest" warning: "Warning: The smallest app partition is nearly full" runs-on: ubuntu-22.04 container: espressif/idf:${{ matrix.idf_ver }} + env: + TARGET_TEST: examples/esp_netif/slip_custom_netif/ + TARGET_TEST_DIR: build_esp32c3_target steps: - name: Checkout esp-protocols uses: actions/checkout@v4 @@ -31,6 +34,16 @@ jobs: python -m pip install idf-build-apps # Build default configs for all targets python ./ci/build_apps.py examples -m examples/.build-test-rules.yml -d -c + # Build target tests + python ./ci/build_apps.py ${TARGET_TEST} -r sdkconfig.ci=target + cd ${TARGET_TEST} + ${GITHUB_WORKSPACE}/ci/clean_build_artifacts.sh `pwd`/${TARGET_TEST_DIR} + zip -qur artifacts.zip ${TARGET_TEST_DIR} + - uses: actions/upload-artifact@v4 + with: + name: slip_target_${{ matrix.idf_ver }} + path: ${{ env.TARGET_TEST }}/artifacts.zip + if-no-files-found: error build_and_run_on_host: if: contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push' @@ -51,3 +64,38 @@ jobs: python ./ci/build_apps.py examples/mqtt -l -t linux timeout 5 ./examples/mqtt/build_linux_default/esp_mqtt_demo.elf | tee test.log || true grep 'MQTT_EVENT_DATA' test.log + + run_on_target: + # Skip running on forks since it won't have access to secrets + if: | + github.repository == 'espressif/esp-protocols' && + ( contains(github.event.pull_request.labels.*.name, 'examples') || github.event_name == 'push' ) + name: Slip example target test + needs: build_all_examples + strategy: + matrix: + idf_ver: ["release-v5.4", "latest"] + runs-on: + - self-hosted + - modem + env: + TARGET_TEST: examples/esp_netif/slip_custom_netif/ + TARGET_TEST_DIR: build_esp32c3_target + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: slip_target_${{ matrix.idf_ver }} + path: ${{ env.TARGET_TEST }}/ci/ + - name: Run Test + working-directory: ${{ env.TARGET_TEST }} + run: | + python -m venv .venv + source .venv/bin/activate + pip install --prefer-binary cryptography pytest-embedded pytest-embedded-serial-esp pytest-embedded-idf pytest-custom_exit_code esptool netifaces + unzip ci/artifacts.zip -d ci + for dir in `ls -d ci/build_*`; do + rm -rf build sdkconfig.defaults + mv $dir build + python -m pytest --log-cli-level DEBUG --target=esp32c3 + done diff --git a/examples/esp_netif/slip_custom_netif/pytest_slip.py b/examples/esp_netif/slip_custom_netif/pytest_slip.py new file mode 100644 index 0000000000..35892e361b --- /dev/null +++ b/examples/esp_netif/slip_custom_netif/pytest_slip.py @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +from __future__ import print_function, unicode_literals + +import subprocess +import time +from threading import Event, Thread + +import netifaces + + +def is_esp32(port): + """ + Check if the given port is connected to an ESP32 using esptool. + """ + try: + result = subprocess.run( + ['esptool.py', '--port', port, 'chip_id'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text=True + ) + return 'ESP32' in result.stdout + except subprocess.CalledProcessError: + return False + + +def run_server(server_stop, port): + print('Launching SLIP netif on port: {}'.format(port)) + try: + arg_list = ['sudo', 'slattach', '-v', '-L', '-s', '115200','-p', 'slip', port] + p = subprocess.Popen(arg_list, stdout=subprocess.PIPE, bufsize=1) + while not server_stop.is_set(): + if p.poll() is not None: + if p.poll() == 16: + print('[SLIP:] Terminated: hang-up received') + break + else: + raise ValueError( + 'ENV_TEST_FAILURE: SLIP terminated unexpectedly with {}' + .format(p.poll())) + time.sleep(0.1) + except Exception as e: + print(e) + raise ValueError('ENV_TEST_FAILURE: Error running SLIP netif') + finally: + p.terminate() + print('SLIP netif stopped') + + +def test_examples_protocol_slip(dut): + + # the PPP test env is reused for SLIP test and it uses three ttyUSB's: two for ESP32 board and another one for the ppp server + server_port = None + for i in ['/dev/ttyUSB0', '/dev/ttyUSB1', '/dev/ttyUSB2']: + if i == dut.serial.port: + print(f'DUT port: {i}') + elif is_esp32(i): + print(f'Some other ESP32: {i}') + else: + print(f'Port for SLIP: {i}') + server_port = i + if server_port is None: + print('ENV_TEST_FAILURE: Cannot locate SLIP port') + raise + # Attach to the SLI netif + server_stop = Event() + t = Thread(target=run_server, args=(server_stop, server_port)) + t.start() + try: + # Setups the SLIP interface + ppp_server_timeout = time.time() + 30 + while 'sl0' not in netifaces.interfaces(): + print( + "SLIP netif hasn't appear yet, list of active netifs:{}" + .format(netifaces.interfaces())) + time.sleep(0.5) + if time.time() > ppp_server_timeout: + raise ValueError( + 'ENV_TEST_FAILURE: SLIP netif failed to setup sl0 interface within timeout' + ) + # Configure the SLIP interface with IP addresses of both ends + cmd = ['sudo', 'ifconfig', 'sl0', '10.0.0.1', 'dstaddr', '10.0.0.2'] + try: + subprocess.run(cmd, check=True) + print('SLIP interface configured successfully.') + except subprocess.CalledProcessError as e: + print(f'Failed to configure SLIP interface: {e}') + # Ping the SLIP interface with 5 packets and 10 seconds timeout + cmd = ['ping', '10.0.0.2', '-c', '5', '-W', '10'] + try: + subprocess.run(cmd, check=True) + print('Pinging SLIP interface successfully.') + except subprocess.CalledProcessError as e: + print(f'Failed to ping SLIP interface: {e}') + raise + + finally: + server_stop.set() + t.join() diff --git a/examples/esp_netif/slip_custom_netif/sdkconfig.ci b/examples/esp_netif/slip_custom_netif/sdkconfig.ci new file mode 100644 index 0000000000..c7cee07789 --- /dev/null +++ b/examples/esp_netif/slip_custom_netif/sdkconfig.ci @@ -0,0 +1,6 @@ +CONFIG_IDF_TARGET="esp32c3" +CONFIG_LWIP_PPP_SUPPORT=y +CONFIG_LWIP_SLIP_SUPPORT=y +CONFIG_EXAMPLE_IPV4=y +CONFIG_EXAMPLE_UART_TX_PIN=6 +CONFIG_EXAMPLE_UART_RX_PIN=7 diff --git a/examples/esp_netif/slip_custom_netif/sdkconfig.defaults b/examples/esp_netif/slip_custom_netif/sdkconfig.defaults index a0f094bcdd..e5847818e3 100644 --- a/examples/esp_netif/slip_custom_netif/sdkconfig.defaults +++ b/examples/esp_netif/slip_custom_netif/sdkconfig.defaults @@ -1,2 +1,5 @@ # Override some defaults to enable SLIP CONFIG_LWIP_SLIP_SUPPORT=y +# Workaround: Enable PPP to let esp_netif know that lwip's netif->state +# will be occupied (by SLIP netif info) +CONFIG_LWIP_PPP_SUPPORT=y