ci: use shared OpenOCD class for GDB test app

This commit is contained in:
Samuel Obuch
2025-05-20 17:29:33 +02:00
parent 0eb74ffcc3
commit 60e64d2464
2 changed files with 26 additions and 85 deletions

View File

@@ -47,9 +47,12 @@ tools/test_apps/system/g1_components:
tools/test_apps/system/gdb: tools/test_apps/system/gdb:
disable_test: disable_test:
- if: IDF_TARGET in ["esp32s3", "esp32c2", "esp32c3", "esp32c5", "esp32c61", "esp32p4"] - if: IDF_TARGET == "esp32p4"
temporary: true temporary: true
reason: lack of runners reason: lack of runners
- if: IDF_TARGET in ["esp32c5", "esp32c61"]
temporary: true
reason: not supported yet # TODO: IDF-13142
tools/test_apps/system/gdb_loadable_elf: tools/test_apps/system/gdb_loadable_elf:
disable_test: disable_test:

View File

@@ -1,72 +1,19 @@
# SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD # SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0 # SPDX-License-Identifier: Unlicense OR CC0-1.0
import json
import logging
import os import os
import re import re
import subprocess import typing
import time
from subprocess import Popen
from typing import Optional
import pexpect import pexpect
import pytest import pytest
from pytest_embedded_idf import IdfDut from pytest_embedded_idf import IdfDut
from pytest_embedded_idf.utils import idf_parametrize from pytest_embedded_idf.utils import idf_parametrize
MAX_RETRIES = 3 if typing.TYPE_CHECKING:
RETRY_DELAY = 3 # seconds from conftest import OpenOCD
def run_openocd(dut: IdfDut) -> Optional[Popen]: def _test_idf_gdb(openocd: 'OpenOCD', dut: IdfDut) -> None:
desc_path = os.path.join(dut.app.binary_path, 'project_description.json')
try:
with open(desc_path, 'r') as f:
project_desc = json.load(f)
except FileNotFoundError:
logging.error('Project description file not found at %s', desc_path)
return None
openocd_scripts = os.getenv('OPENOCD_SCRIPTS')
if not openocd_scripts:
logging.error('OPENOCD_SCRIPTS environment variable is not set.')
return None
debug_args = project_desc.get('debug_arguments_openocd')
if not debug_args:
logging.error("'debug_arguments_openocd' key is missing in project_description.json")
return None
cmd = ['openocd'] + ['-s', openocd_scripts] + debug_args.split()
# For debug purpose, make the value '4'
ocd_env = os.environ.copy()
ocd_env['LIBUSB_DEBUG'] = '1'
for attempt in range(1, MAX_RETRIES + 1):
logging.info('Attempt %d: Running %s', attempt, cmd)
with open(os.path.join(dut.logdir, 'ocd.txt'), 'w') as ocd_log:
try:
ocd = subprocess.Popen(cmd, stdout=ocd_log, stderr=ocd_log, env=ocd_env)
time.sleep(1)
# Check if the process is running successfully
if ocd.poll() is None:
return ocd
else:
logging.error('OpenOCD exited with error code %d', ocd.returncode)
except subprocess.SubprocessError as e:
logging.error('Error running OpenOCD: %s', e)
logging.warning("OpenOCD couldn't be run. Retrying in %d seconds...", RETRY_DELAY)
time.sleep(RETRY_DELAY)
logging.error('Failed to run OpenOCD after %d attempts.', MAX_RETRIES)
return None
def _test_idf_gdb(dut: IdfDut) -> None:
# Need to wait a moment to connect via OpenOCD after the hard reset happened. # Need to wait a moment to connect via OpenOCD after the hard reset happened.
# Along with this check that app runs ok # Along with this check that app runs ok
dut.expect('Hello world!') dut.expect('Hello world!')
@@ -74,36 +21,27 @@ def _test_idf_gdb(dut: IdfDut) -> None:
# Don't need to have output from UART anymore # Don't need to have output from UART anymore
dut.serial.stop_redirect_thread() dut.serial.stop_redirect_thread()
ocd = run_openocd(dut) with openocd.run(), open(os.path.join(dut.logdir, 'gdb.txt'), 'w') as gdb_log, pexpect.spawn(
assert ocd f'idf.py -B {dut.app.binary_path} gdb --batch',
timeout=60,
try: logfile=gdb_log,
with open(os.path.join(dut.logdir, 'gdb.txt'), 'w') as gdb_log, pexpect.spawn( encoding='utf-8',
f'idf.py -B {dut.app.binary_path} gdb --batch', codec_errors='ignore',
timeout=60, ) as p:
logfile=gdb_log, p.expect(re.compile(r'add symbol table from file.*bootloader.elf'))
encoding='utf-8', p.expect(
codec_errors='ignore', re.compile(r'add symbol table from file.*rom.elf')
) as p: ) # if fail here: add target support here https://github.com/espressif/esp-rom-elfs
p.expect(re.compile(r'add symbol table from file.*bootloader.elf')) p.expect_exact('hit Temporary breakpoint 1, app_main ()')
p.expect(
re.compile(r'add symbol table from file.*rom.elf')
) # if fail here: add target support here https://github.com/espressif/esp-rom-elfs
p.expect_exact('hit Temporary breakpoint 1, app_main ()')
finally:
# Check if the process is still running
if ocd.poll() is None:
ocd.terminate()
ocd.kill()
@pytest.mark.jtag @pytest.mark.jtag
@idf_parametrize('target', ['esp32', 'esp32s2'], indirect=['target']) @idf_parametrize('target', ['esp32', 'esp32c2', 'esp32s2'], indirect=['target'])
def test_idf_gdb(dut: IdfDut) -> None: def test_idf_gdb(openocd: 'OpenOCD', dut: IdfDut) -> None:
_test_idf_gdb(dut) _test_idf_gdb(openocd, dut)
@pytest.mark.usb_serial_jtag @pytest.mark.usb_serial_jtag
@idf_parametrize('target', ['esp32c6', 'esp32h2'], indirect=['target']) @idf_parametrize('target', ['esp32s3', 'esp32c3', 'esp32c6', 'esp32h2'], indirect=['target'])
def test_idf_gdb_usj(dut: IdfDut) -> None: def test_idf_gdb_usj(openocd: 'OpenOCD', dut: IdfDut) -> None:
_test_idf_gdb(dut) _test_idf_gdb(openocd, dut)